
/*关于按键：
遍历是一个简单的事，定义好parent，child, dn_sibble, up_sibble即可。
处理复杂的是叶子菜单项的定义（定义那些操作属于一个叶子菜单项，如定义了CAL_In）和处理。
工作量大，要编写每个叶子菜单项。
*/
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>


#include "bsp.h"
#include "menu_seg.h"
#include "menu_seg_helper.h"
#include "key.h"
#include "threads.h"
#include "dbgUart.h"
#include "parameter.h"
#include "weight_polyline.h"
#include "ds28e25.h"
#include "preset_point.h"
#include "drv_ch423s.h"

#include "menu_Fn.h"
#include "menu_Pn.h"
#include "menu_Hold.h"
#include "menu_Test_io.h"
#include "menu_IOn.h"
#include "menu_test.h"
#include "menu_rst.h"


extern uint8_t flag_para_update_adc;
extern uint8_t flag_para_update_dac;
extern uint8_t flag_para_update_com_plc;		//通信参数。
extern uint8_t flag_para_update_fir;
extern uint8_t flag_ma_cal;

extern int32_t para_to_flash_2(uint32_t );

#ifdef OFFSET_DIV_N_F
extern float offset_div_n_f_man;			//手动触发
extern float offset_div_n_f_pwr_on;			//上电自动清零
extern float offset_div_n_f_trace;			//零点跟踪
extern float offset_div_n_f_tare;			//去皮操作。				
#else
extern int32_t offset_man;					//手动归零的偏移量				在显示模式下，按下zero键；显示值在清零范围。			-1*显示值 --> offset
extern int32_t offset_pwr_on;				//上电自动清零的偏移量			上电；上电清零开关有效；显示值在清零范围。				-1*显示值 --> offset_pwr_on
extern int32_t offset_trace;				//零点跟踪的偏移量				显示值在跟踪范围；持续时间超过1.6秒。					-1*显示值 --> offset_zero_range
#endif



/*第1级菜单项。
*/
extern MENU_ITEM setup;
extern MENU_ITEM hold;
extern MENU_ITEM spoint;
extern MENU_ITEM io_def;
extern MENU_ITEM test_io;
extern MENU_ITEM test;
extern MENU_ITEM rst;


void offset_clear(void);
void key_F1_4(MSG_U msg);		//功能同key_Fn()，增加了小数点。



static int32_t mv_to_ad(int32_t uv);

/*叶子菜单项的按键处理函数。
*/
//void leaf_Fn_ma_cal_4K(MSG_U msg);		//4.000mA  -> 4K
//void leaf_Fn_ma_cal_12K(MSG_U msg);		//12.000mA -> 12K
//void leaf_Fn_ma_cal_20K(MSG_U msg);		//20.000mA -> 20K
//void leaf_Fn_ma_cal_24K(MSG_U msg);		//24.000mA -> 24K
void leaf_Fn_ma_mv_cal(MSG_U msg);		//统一以上独立的校准函数。


void leaf_Fn_cal_in(MSG_U msg);
void leaf_Fn_cal_pt(MSG_U msg);
void leaf_Fn_cal_1d(MSG_U msg);
void leaf_Fn_cal_cp(MSG_U msg);
void leaf_Fn_cal_t(MSG_U msg);			//零点mv值
void leaf_Fn_cal_load_n(MSG_U msg);		//统一了_load1~load4的叶子菜单项函数。
void leaf_Fn_cal_load1(MSG_U msg);		//有砝码标定第1点的叶子菜单项函数。
void leaf_Fn_cal_load2(MSG_U msg);		//有砝码标定第2点的叶子菜单项函数。
void leaf_Fn_cal_load3(MSG_U msg);		//有砝码标定第3点的叶子菜单项函数。
void leaf_Fn_cal_load4(MSG_U msg);		//有砝码标定第4点的叶子菜单项函数。
void leaf_Fn_cal_siocal(MSG_U msg);
void leaf_Fn_cal_pass(MSG_U msg);
//void leaf_Fn_cal_RdP(MSG_U msg);		//CAL下读取DS28E中保存的标定参数：point[]，最大量程。
//void leaf_Fn_cal_SaP(MSG_U msg);		//CAL下保存标定参数（point[]，最大量程）到DS28E。

static void leaf_Fn_cal_t_noload(MSG_U msg);	//无砝码零点标定的叶子菜单项函数。
static void leaf_Fn_cal_Load_noload(MSG_U msg);	//无砝码加载点标定的叶子菜单项函数。

void leaf_Fn_test_child(MSG_U msg);

static void leaf_Fn_rst(MSG_U msg);


//
static void init_top_menu(void);

void init_ma_cal_menu(void);				//mA修正。
static void init_CALn_menu(void);

INT_MENU int_menu;
VAR_MENU var_menu;

//菜单项（不用添加.f_enter=NULL，因为static 类型变量，默认为0，即NULL）

static MENU_ITEM cal=  		{.content="Cal   ", .f_enter=NULL};


//static MENU_ITEM F5=		{.content="F5     "};
//static MENU_ITEM F6=		{.content="F6     "};
//static MENU_ITEM F7=		{.content="F7     "};

static MENU_ITEM mA_Cal=		{.content="i 4000", .f_enter=NULL};	//
	   MENU_ITEM mA_Cal_4K=		{.id=4,  .content="i 4.000", .f_enter=NULL};
static MENU_ITEM mA_Cal_12K=	{.id=12, .content="i12.000", .f_enter=NULL};
static MENU_ITEM mA_Cal_20K=	{.id=20, .content="i20.000", .f_enter=NULL};
static MENU_ITEM mA_Cal_24K=	{.id=24, .content="i24.000", .f_enter=NULL};	
static MENU_ITEM mV_Cal_0=		{.id=0, .content="v 0.000", .f_enter=NULL};
static MENU_ITEM mV_Cal_5=		{.id=5, .content="v 5.000", .f_enter=NULL};	

static MENU_ITEM CAL_In=		{.content="PASS  "};	//
static MENU_ITEM CAL_Pt=		{.content="Pt    "};
static MENU_ITEM CAL_1d=		{.content="1d    "};
static MENU_ITEM CAL_CP=		{.content="CP    "};
static MENU_ITEM CAL_t=			{.id= 0, .content="t     "};
//static MENU_ITEM CAL_O=		{.content="O      "};
static MENU_ITEM CAL_Load1=		{.id= 1, .content="Load1 "};
static MENU_ITEM CAL_Load2=		{.id= 2, .content="Load2 "};
static MENU_ITEM CAL_Load3=		{.id= 3, .content="Load3 "};
static MENU_ITEM CAL_Load4=		{.id= 4, .content="Load4 "};
static MENU_ITEM CAL_Sen=		{.content="Sen   "};
//static MENU_ITEM CAL_C=		{.content="C      "};
static MENU_ITEM CAL_Siocal=	{.content="Siocal"};
static MENU_ITEM CAL_Pass=		{.content="Pass  "};
static MENU_ITEM CAL_RdP=		{.content="rd P  "};		//读取单线芯片的资料
static MENU_ITEM CAL_SaP=		{.content="SA P  "};		//保存单线芯片的资料

static MENU_ITEM CAL_t_noload=		{.content="000000"};	//无砝码的零点标定。
static MENU_ITEM CAL_Load_noload=	{.content="000000"};	//无砝码的加载点标定。



uint32_t update_para_to_flash=0;		//是否更新参数到FLASH。准备作废。
MENU_ITEM* cur_item= NULL;				//当前菜单项（遍历菜单项时用）。



/*初始化菜单项（所有级的菜单项）。
*/
void menu_init(void)
{
	init_top_menu();
	
	//setup菜单
	init_Fn_menu();	


	//cal菜单
	init_CALn_menu();

	init_Pn_menu();

	init_Hn_menu();
	init_IOn_menu();
	
	init_test_io_menu();
	init_test_menu();
	init_rst_menu();	
}



/*
*/
MENU_ITEM* get_first_item(void)
{
	return (MENU_ITEM*)&setup;
}



/*
*/
static void init_top_menu(void)
{
	//setup...test形成一个单向环形列表。
	setup.parent= NULL;
	setup.child= get_Fn_top();	//原值为FIN.
	setup.sibble= (MENU_ITEM*)&cal;
	setup.up_sibble= (MENU_ITEM*)&rst;
	setup.f_key= key_Fn;
	
	init_ma_cal_menu();
	
	cal.parent= NULL;
	cal.child= (MENU_ITEM*)&CAL_In;
	cal.sibble= (MENU_ITEM*)&spoint;
	cal.up_sibble= (MENU_ITEM*)&setup;
	cal.f_key= key_Fn;
	
	spoint.parent= NULL;
	spoint.child= get_Pn_top();
	spoint.sibble= (MENU_ITEM*)&hold;
	spoint.up_sibble= (MENU_ITEM*)&cal;
	spoint.f_key= key_Fn;
	
	hold.parent= NULL;
	hold.child= get_Hold_top();
	hold.sibble= (MENU_ITEM*)&io_def;
	hold.up_sibble= (MENU_ITEM*)&spoint;
	hold.f_key= key_Fn;
	
	io_def.parent= NULL;
	io_def.child= get_IOn_top();		//.child指向下一级菜单项，即下一级菜单项中的第1个。
	io_def.sibble= (MENU_ITEM*)&test_io;
	io_def.up_sibble= (MENU_ITEM*)&hold;
	io_def.f_key= key_Fn;

	test_io.parent= NULL;
	test_io.child= get_test_io_top();
	test_io.sibble= (MENU_ITEM*)&test;
	test_io.up_sibble= (MENU_ITEM*)&io_def;
	test_io.f_key= key_Fn;
	
	test.parent= NULL;
	test.child= get_test_top();
	test.sibble= (MENU_ITEM*)&rst;
	test.up_sibble= (MENU_ITEM*)&test_io;
	test.f_key= key_Fn;

	rst.parent= NULL;
	rst.child= get_rst_top();
	rst.sibble= (MENU_ITEM*)&setup;
	rst.up_sibble= (MENU_ITEM*)&test;
	rst.f_key= key_Fn;
}






/*mA(mV)_Cal_xxx菜单项的父菜单是setup。
setup时按Enter键，进入F1->F2...
setup时按OPT+MODE键，进入mA_Cal_4K -> mA_Cal_12K...
*/
void init_ma_cal_menu(void)
{
	MENU_ITEM* parent= (MENU_ITEM*)&setup;
	
	mA_Cal_4K.parent= parent;		//父级为空，则返回称重状态。现在父是setup，但setup的child中无mA_Cal_4K。
	mA_Cal_4K.child= NULL;
	mA_Cal_4K.sibble=(MENU_ITEM*) &mA_Cal_12K;
	mA_Cal_4K.up_sibble= (MENU_ITEM*) &mV_Cal_5;
	mA_Cal_4K.f_key= leaf_Fn_ma_mv_cal;
	
	mA_Cal_12K.parent= parent;		//父级为空，则返回称重状态。
	mA_Cal_12K.child= NULL;
	mA_Cal_12K.sibble= (MENU_ITEM*) &mA_Cal_20K;
	mA_Cal_12K.up_sibble= NULL;
	mA_Cal_12K.f_key= leaf_Fn_ma_mv_cal;
	
	mA_Cal_20K.parent= parent;		//父级为空，则返回称重状态。
	mA_Cal_20K.child= NULL;
	mA_Cal_20K.sibble= (MENU_ITEM*) &mA_Cal_24K;
	mA_Cal_20K.up_sibble= NULL;
	mA_Cal_20K.f_key= leaf_Fn_ma_mv_cal;

	mA_Cal_24K.parent= parent;		//父级为空，则返回称重状态。
	mA_Cal_24K.child= NULL;
	mA_Cal_24K.sibble= (MENU_ITEM*) &mV_Cal_0;
	mA_Cal_24K.up_sibble= NULL;
	mA_Cal_24K.f_key= leaf_Fn_ma_mv_cal;

	mV_Cal_0.parent= parent;		//父级为空，则返回称重状态。
	mV_Cal_0.child= NULL;
	mV_Cal_0.sibble= (MENU_ITEM*) &mV_Cal_5;
	mV_Cal_0.up_sibble= &mA_Cal_24K;
	mV_Cal_0.f_key= leaf_Fn_ma_mv_cal;

	mV_Cal_5.parent= parent;		//父级为空，则返回称重状态。
	mV_Cal_5.child= NULL;
	mV_Cal_5.sibble= (MENU_ITEM*) &mA_Cal_4K;
	mV_Cal_5.up_sibble= &mV_Cal_0;
	mV_Cal_5.f_key= leaf_Fn_ma_mv_cal;
	
}




/*
static MENU_ITEM CAL_Pt={.content="Pt"};
static MENU_ITEM CAL_1d={.content="1d"};
static MENU_ITEM CAL_CP={.content="CP"};
static MENU_ITEM CAL_t={.content="t"};
static MENU_ITEM CAL_O={.content="O"};
static MENU_ITEM CAL_Load1={.content="Load1"};
static MENU_ITEM CAL_Load2={.content="Load2"};
static MENU_ITEM CAL_Load3={.content="Load3"};
static MENU_ITEM CAL_Load4={.content="Load4"};
static MENU_ITEM CAL_Sen={.content="Sen"};
static MENU_ITEM CAL_Siocal={.content="Siocal"};
static MENU_ITEM CAL_Pass={.content="Pass"};
*/
static void init_CALn_menu(void)
{
	MENU_ITEM* parent;
	MENU_ITEM* head;
	MENU_ITEM* tail;
	
	parent= (MENU_ITEM*)&cal;
	head= (MENU_ITEM*)&CAL_Pt;
	tail= (MENU_ITEM*)&CAL_Pass;
	
	
	//CAL_Pt->...CAL_Pass->是一个单向循环。
	CAL_In.parent= parent;
	CAL_In.sibble= (MENU_ITEM*)&CAL_Pt;
	CAL_In.up_sibble= NULL;
	CAL_In.f_key= leaf_Fn_cal_in;	//_lefa_Fn是叶子菜单项函数。
	
	CAL_Pt.parent= parent;
	CAL_Pt.sibble= (MENU_ITEM*)&CAL_1d;
	CAL_Pt.up_sibble= NULL;
	//CAL_Pt.f_key= leaf_Fn_cal_pt;
	CAL_Pt.f_key= leaf_Fn_select_idx;
	strcpy(CAL_Pt.para_name, "CAL_Pt");
	CAL_Pt.tbl= (void*)_tbl_pt_pos;	//小数点位数=小数位数。
	CAL_Pt.tbl_type= TBL_TYPE_STR;
	CAL_Pt.ppara_idx= &para_xxx.pt_pos_idx;
	
	CAL_1d.parent= parent;
	CAL_1d.sibble= (MENU_ITEM*)&CAL_CP;
	CAL_1d.up_sibble= NULL;
	CAL_1d.f_key= leaf_Fn_cal_1d;		//设置最小分度的函数，未使用统一函数：是参数值，非索引值。	
	
	CAL_CP.parent= parent;
	CAL_CP.sibble= (MENU_ITEM*)&CAL_t;
	CAL_CP.up_sibble= NULL;
	CAL_CP.f_key= leaf_Fn_cal_cp;
	
	CAL_t.parent= parent;
	CAL_t.sibble= (MENU_ITEM*)&CAL_Load1;
	CAL_t.up_sibble= NULL;
	CAL_t.f_key= leaf_Fn_cal_t;
	
	CAL_Load1.parent= parent;
	CAL_Load1.sibble= (MENU_ITEM*)&CAL_Load2;
	CAL_Load1.up_sibble= NULL;
	CAL_Load1.f_key= leaf_Fn_cal_load_n;
	
	CAL_Load2.parent= parent;
	CAL_Load2.sibble= (MENU_ITEM*)&CAL_Load3;
	CAL_Load2.up_sibble= NULL;
	CAL_Load2.f_key= leaf_Fn_cal_load_n;
	
	CAL_Load3.parent= parent;
	CAL_Load3.sibble= (MENU_ITEM*)&CAL_Load4;
	CAL_Load3.up_sibble= NULL;
	CAL_Load3.f_key= leaf_Fn_cal_load_n;
	
	CAL_Load4.parent= parent;
	CAL_Load4.sibble= (MENU_ITEM*)&CAL_Siocal;
	CAL_Load4.up_sibble= NULL;
	CAL_Load4.f_key= leaf_Fn_cal_load_n;
	
	CAL_Siocal.parent= parent;
	CAL_Siocal.sibble= (MENU_ITEM*)&CAL_Pass;
	CAL_Siocal.up_sibble= NULL;
	CAL_Siocal.f_key= leaf_Fn_select_idx;
	strcpy(CAL_Siocal.para_name, "SicoaL");
	CAL_Siocal.tbl= (void*)_tbl_off_on;		//off,on选择。
	CAL_Siocal.tbl_type= TBL_TYPE_STR;
	CAL_Siocal.ppara_idx= &para_self.ser_cal_sw;
	
	CAL_Pass.parent= parent;
	CAL_Pass.sibble= head;
	CAL_Pass.up_sibble= NULL;
	CAL_Pass.f_key= leaf_Fn_cal_pass;
	
	
	//零点标定菜单下的子菜单项：
	CAL_t.child= &CAL_t_noload; 
	CAL_t_noload.parent= &CAL_t;
	CAL_t_noload.sibble= NULL;
	CAL_t_noload.up_sibble= NULL;
	CAL_t_noload.f_key= leaf_Fn_cal_t_noload;
	
	//加载点1标定菜单下的子菜单项：
	CAL_Load1.child= &CAL_Load_noload; 
	CAL_Load_noload.parent= &CAL_Load1;
	CAL_Load_noload.sibble= NULL;
	CAL_Load_noload.up_sibble= NULL;
	CAL_Load_noload.f_key= leaf_Fn_cal_Load_noload;
		
	
//	CAL_RdP.parent= parent;
//	CAL_RdP.sibble= (MENU_ITEM*)&CAL_SaP;
//	CAL_RdP.f_key= leaf_Fn_cal_RdP;
//	
//	CAL_SaP.parent= parent;
//	CAL_SaP.sibble= head;
//	CAL_SaP.f_key= leaf_Fn_cal_SaP;
}



/*模式量电流或电压校准函数。
*/
void leaf_Fn_ma_mv_cal(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 6;	//有效范围：1~6。左起第1个为1。
	
	static uint16_t val_change;
	uint16_t key;
	uint16_t tmp16;
	char tmp8[8];				//共8B，包含第1个' '（灯状态）和UI的6个字符和1个'\0'。
	char str[48];
	char str_i[7];
	
	
	if(MSG_TYPE_KEY == msg.type){
		key= msg.key;  

		switch (sta){
			case 0:	//显示着"i 4000"。
				if(KEY_K1_ESC == key){
					sprintf(str, "sfsfd");
					uartS(str);
					
					//返回上级菜单
					if(cur_item->parent){
						cur_item= cur_item->parent;	
						seg_updata(cur_item->content);	
					}
					else{
						uartS("\nerr:no parent");
					}
					
					flag_ma_cal= 0;
					seg_flash_all(0);
				}
				else if(KEY_K2_OPT == key){
					//nothing
				}
				else if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);
				}
				else if(KEY_K4_ENTER == key){
					//调整
					if(4 == cur_item->id)
						tmp16= para_self.da4K;
					else if(12 == cur_item->id)
						tmp16= para_self.da12K;
					else if(20 == cur_item->id)
						tmp16= para_self.da20K;
					else if(24 == cur_item->id)
						tmp16= para_self.da24K;
					else if(0 == cur_item->id)
						tmp16= para_self.da0V;
					else if(5 == cur_item->id)
						tmp16= para_self.da5V;
					else{
						//error
					}
					
					//!!int_menu是全局变量。
					int_menu.dig= 6;		
					int_menu.neg= 0;
					int_menu.val= tmp16;
					int_menu.max= 65535;
					int_menu.min= 0;
					
					sta= 1;
					sprintf(str_i, "%06d", int_menu.val); 
					seg_updata(str_i);
				
					//第1个‘0’闪
					int_menu.pos= SEG_L_1;
					x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
					
					flag_ma_cal= 1;
					osDelay(100);
					dac_out(int_menu.val);
					
					sta= 1;
				}
				else{
					//nothing
				}
				
				break;
			
			case 1:	//显示着4.000mA对应的DA值，通过MODE键调小，OPT键调大，ENTER键盘保存，ESC键返回sta 0并显示"i 4000"。			
				if(KEY_K1_ESC == key){
					seg_updata(cur_item->content);	//显示"i 4000"或"i12000","i20000","i20000", "i240000"。
					
					flag_ma_cal= 0;
					sta= 0;
					x_seg_flash_all(0);
				}
				else if(key == KEY_K2_OPT){
					int_menu_inc_one_seg(0);	//65536/24.000≈2.7，即大约调整3，对应1uA。
					
					dac_out(int_menu.val);	
				}
				else if(key == KEY_K3_MODE){
					int_menu_change_pos();
				}	
				else if(KEY_K4_ENTER == key){
					//保存调整值到FLASH参数区。
					if(4 == cur_item->id){
						tmp16= para_self.da4K;
						para_self.da4K= int_menu.val;						
					}
					else if(12 == cur_item->id){
						tmp16= para_self.da12K;
						para_self.da12K= int_menu.val;
					}
					else if(20 == cur_item->id){
						tmp16= para_self.da20K;
						para_self.da20K= int_menu.val;
					}
					else if(24 == cur_item->id){
						tmp16= para_self.da24K;
						para_self.da24K= int_menu.val;
					}
					else if(0 == cur_item->id){
						tmp16= para_self.da0V;
						para_self.da0V= int_menu.val;
					}
					else if(5 == cur_item->id){
						tmp16= para_self.da5V;
						para_self.da5V= int_menu.val;
					}
					else{
						//error
					}
					
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
						sprintf(str, "\nsave %s", cur_item->content);
						uartS(str);
					
						cur_item= cur_item->sibble;	
						seg_updata(cur_item->content);
						
						
						flag_ma_cal= 0;
						sta= 0;
						x_seg_flash_all(0);
					}
					else{
						//保存失败，恢复旧值。
						if(4 == cur_item->id){
							para_self.da4K= tmp16;						
						}
						else if(12 == cur_item->id){
							para_self.da12K= tmp16;
						}
						else if(20 == cur_item->id){
							para_self.da20K= tmp16;
						}
						else if(24 == cur_item->id){
							para_self.da24K= tmp16;
						}						
						else if(0 == cur_item->id){
							para_self.da0V= tmp16;
						}
						else if(5 == cur_item->id){
							para_self.da5V= tmp16;
						}
						
						x_seg_flash_all(0);
						seg_updata("Err00F");
						
						sprintf(str, "\nerr:save %s", cur_item->content);
						uartS(str);
						
						osDelay(1000);
					}
				}
				else{
				}
				
				break;
			
			default:
				break;
		}
	}
}





///*
//*/
//void leaf_Fn_ma_cal_4K(MSG_U msg)
//{
//	static uint8_t sta= 0;
//	static uint8_t idx_seg= 6;	//有效范围：1~6。左起第1个为1。
//	
//	static uint16_t val_change;
//	uint16_t key;
//	char tmp8[8];				//共8B，包含第1个' '（灯状态）和UI的6个字符和1个'\0'。
//	char str[48];
//	
//	
//	if(MSG_TYPE_KEY == msg.type){
//		key= msg.key;  

//		switch (sta){
//			case 0:	//显示着"i 4000"。
//				if(KEY_K3_MODE == key){
//					//在同级菜单循环切换。
//					cur_item= cur_item->sibble;	
//					seg_updata(cur_item->content);
//				}
//				else if(KEY_K4_ENTER == key){
//					//调整
//					show_val(para_self.da4K , tmp8);
//					seg_updata(tmp8);
//					val_change= para_self.da4K;
//					
//					flag_ma_cal= 1;
//					osDelay(100);
//					dac_out(val_change*16);
//					
//					sta= 1;
//					idx_seg= 4;
//					set_one_seg_flash(idx_seg, SEG_FLASH);
//				}
//				else if(KEY_K1_ESC == key){	
//					sprintf(str, "sfsfd");
//					uartS(str);
//					
//					//返回上级菜单
//					if(cur_item->parent){
//						cur_item= cur_item->parent;	
//						seg_updata(cur_item->content);	
//					}
//					else{
//						uartS("\nerr:no parent");
//					}
//					
//					flag_ma_cal= 0;
//					seg_flash_all(0);
//				}
//				
//				break;
//			
//			case 1:	//显示着4.000mA对应的DA值，通过MODE键调小，OPT键调大，ENTER键盘保存，ESC键返回sta 0并显示"i 4000"。			
//				if(KEY_K1_ESC == key){
//					//返回状态0。
//					seg_updata("i 4000");
//					
//					flag_ma_cal= 0;
//					sta= 0;
//					seg_flash_all(0);
//				}
//				else if(key == KEY_K2_OPT){
//					if(0 == strcmp(ITEM_ANA_V_STR, _tbl_ana_out[para_self.ana_out_idx])){
//						inc_one_seg(idx_seg);
//					}
//					else
//						inc_one_seg(idx_seg);
//					
//					//将当前显示值拷贝到tmp8[1~6]。
//					seg_copy_to_tmp(tmp8);		
//					tmp8[0]= ' ';
//					tmp8[7]= '\0';
//					int32_t x= atoi(tmp8);
//					if(4095< x)
//						x= 4095;
//					
//					//设置7760的DA值。
//					dac_out(x*16);	
//				}
//				else if(key == KEY_K3_MODE){
//					set_one_seg_flash(idx_seg, SEG_LIGHT);
//					
//					idx_seg++;
//					if(6< idx_seg)
//						idx_seg= 1;
//					set_one_seg_flash(idx_seg, SEG_FLASH);
//					
//					//将当前显示值拷贝到tmp8[1~6]。
//					seg_copy_to_tmp(tmp8);		
//					tmp8[0]= ' ';
//					tmp8[7]= '\0';
//					int32_t x= atoi(tmp8);
//					if(4095< x)
//						x= 4095;
//					
//					//设置7760的DA值。
//					dac_out(x*16);	
//				}	
//				else if(KEY_K4_ENTER == key){
//					//保存调整值到FLASH参数区。
//					seg_copy_to_tmp(tmp8);		
//					tmp8[0]= ' ';
//					tmp8[7]= '\0';
//					int32_t x= atoi(tmp8);
//					if(4095< x)
//						x= 4095;
//									
//					uint16_t tmp16= para_self.da4K;
//					para_self.da4K= (uint16_t)x;
//					
//					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
//						uartS("\nsave para_self.da4K");
//					
//						cur_item= cur_item->sibble;	
//						seg_updata(cur_item->content);
//						
//						
//						flag_ma_cal= 0;
//						sta= 0;
//						seg_flash_all(0);
//					}
//					else{		
//						para_self.da4K= tmp16;		//保存失败，恢复旧值（断电完蛋）。
//						
//						seg_flash_all(0);
//						seg_updata("Err00F");
//						
//						uartS("\nerr save para_self.da4K");
//						osDelay(1000);
//					}
//				}
//				else{
//				}
//				
//				break;
//			
//			default:
//				break;
//		}
//	}
//}



//void leaf_Fn_ma_cal_12K(MSG_U msg)
//{
//	static uint8_t sta= 0;
//	static uint8_t idx_seg= 1;	//有效范围：1~6。左起第1个为1。	
//	static uint16_t val_change;
//	uint16_t key;
//	char tmp8[8];				//共8B，包含第1个' '（灯状态）和UI的6个字符和1个'\0'。
//	
//	
//	
//	if(MSG_TYPE_KEY == msg.type){
//		key= msg.key;
//		
//		switch (sta){
//			case 0:	//显示着"i12000"。
//				if(KEY_K3_MODE == key){
//					//在同级菜单循环切换。
//					cur_item= cur_item->sibble;	
//					seg_updata(cur_item->content);
//				}
//				else if(KEY_K4_ENTER == key){
//					//调整
//					show_val(para_self.da12K , tmp8);
//					seg_updata(tmp8);
//					val_change= para_self.da12K;
//					
//					flag_ma_cal= 1;
//					osDelay(100);
//					dac_out(val_change*16);
//					
//					sta= 1;
//					idx_seg= 3;
//					set_one_seg_flash(idx_seg, SEG_FLASH);
//				}
//				else if(KEY_K1_ESC == key){	
//					//返回上级菜单
//					if(cur_item->parent){
//						cur_item= cur_item->parent;	
//						seg_updata(cur_item->content);	
//					}
//					else{
//						uartS("\nerr:no parent");
//					}
//					
//					flag_ma_cal= 0;
//					seg_flash_all(0);
//				}
//				break;
//			
//			case 1:	//显示着4.000mA对应的DA值，通过MODE键调小，OPT键调大，ENTER键盘保存，ESC键返回sta 0并显示"i 4000"。
//				if(KEY_K1_ESC == key){
//					//返回状态0。
//					seg_updata("i12000");
//					
//					flag_ma_cal= 0;
//					sta= 0;
//					seg_flash_all(0);
//				}
//				else if(key == KEY_K2_OPT){
//					if(0 == strcmp(ITEM_ANA_V_STR, _tbl_ana_out[para_self.ana_out_idx])){
//						inc_one_seg(idx_seg);
//					}
//					else
//						inc_one_seg(idx_seg);
//					
//					//将当前显示值拷贝到tmp8[1~6]。
//					seg_copy_to_tmp(tmp8);		
//					tmp8[0]= ' ';
//					tmp8[7]= '\0';
//					int32_t x= atoi(tmp8);
//					if(4095< x)
//						x= 4095;
//					
//					//设置7760的DA值。
//					dac_out(x*16);	
//				}
//				else if(key == KEY_K3_MODE){
//					set_one_seg_flash(idx_seg, SEG_LIGHT);
//					
//					idx_seg++;
//					if(6< idx_seg)
//						idx_seg= 1;
//					set_one_seg_flash(idx_seg, SEG_FLASH);
//					
//					//将当前显示值拷贝到tmp8[1~6]。
//					seg_copy_to_tmp(tmp8);		
//					tmp8[0]= ' ';
//					tmp8[7]= '\0';
//					int32_t x= atoi(tmp8);
//					if(4095< x)
//						x= 4095;
//					
//					//设置7760的DA值。
//					dac_out(x*16);	
//				}		
//				else if(KEY_K4_ENTER == key){
//					//保存调整值到FLASH参数区。
//					seg_copy_to_tmp(tmp8);		
//					tmp8[0]= ' ';
//					tmp8[7]= '\0';
//					int32_t x= atoi(tmp8);
//					if(4095< x)
//						x= 4095;
//					
//					uint16_t tmp16= para_self.da12K;
//					para_self.da12K= (uint16_t)x;
//					
//					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
//						uartS("\nsave para_self.da12K");
//					
//						cur_item= cur_item->sibble;	
//						seg_updata(cur_item->content);
//						
//						
//						flag_ma_cal= 0;
//						sta= 0;
//						seg_flash_all(0);
//					}
//					else{		
//						para_self.da12K= tmp16;		//保存失败，恢复旧值（断电完蛋）。
//						
//						seg_flash_all(0);
//						seg_updata("Err00F");
//						
//						uartS("\nerr save para_self.da12K");
//						osDelay(1000);
//					}
//				}
//				else{
//				}
//				break;
//			
//			default:
//				break;
//		}
//	}
//}



//void leaf_Fn_ma_cal_20K(MSG_U msg)
//{
//	static uint8_t sta= 0;
//	static uint8_t idx_seg= 1;	//有效范围：1~6。左起第1个为1。
//	static uint16_t val_change;
//	uint16_t key;
//	char tmp8[8];				//共8B，包含第1个' '（灯状态）和UI的6个字符和1个'\0'。
//	
//	
//	
//	if(MSG_TYPE_KEY == msg.type){
//		key= msg.key;
//		
//		switch (sta){
//			case 0:	//显示着"i 4000"。
//				if(KEY_K3_MODE == key){
//					//在同级菜单循环切换。
//					cur_item= cur_item->sibble;	
//					seg_updata(cur_item->content);
//				}
//				else if(KEY_K4_ENTER == key){
//					//调整
//					show_val(para_self.da20K , tmp8);
//					seg_updata(tmp8);
//					val_change= para_self.da20K;
//					
//					flag_ma_cal= 1;
//					osDelay(100);
//					dac_out(val_change*16);
//					
//					sta= 1;
//					idx_seg= 3;
//					set_one_seg_flash(idx_seg, SEG_FLASH);
//				}
//				else if(KEY_K1_ESC == key){	
//					//返回上级菜单
//					if(cur_item->parent){
//						cur_item= cur_item->parent;	
//						seg_updata(cur_item->content);	
//					}
//					else{
//						uartS("\nerr:no parent");
//					}
//					
//					flag_ma_cal= 0;
//					seg_flash_all(0);
//				}
//				break;
//			
//			case 1:	//显示着4.000mA对应的DA值，通过MODE键调小，OPT键调大，ENTER键盘保存，ESC键返回sta 0并显示"i 4000"。
//				if(KEY_K1_ESC == key){
//					//返回状态0。
//					seg_updata("i20000");
//					
//					flag_ma_cal= 0;
//					sta= 0;
//					seg_flash_all(0);
//				}
//				else if(key == KEY_K2_OPT){
//					if(0 == strcmp(ITEM_ANA_V_STR, _tbl_ana_out[para_self.ana_out_idx])){
//						inc_one_seg(idx_seg);
//					}
//					else
//						inc_one_seg(idx_seg);
//					
//					//将当前显示值拷贝到tmp8[1~6]。
//					seg_copy_to_tmp(tmp8);		
//					tmp8[0]= ' ';
//					tmp8[7]= '\0';
//					int32_t x= atoi(tmp8);
//					if(4095< x)
//						x= 4095;
//					
//					//设置7760的DA值。
//					dac_out(x*16);	
//				}
//				else if(key == KEY_K3_MODE){
//					set_one_seg_flash(idx_seg, SEG_LIGHT);
//					
//					idx_seg++;
//					if(6< idx_seg)
//						idx_seg= 1;
//					set_one_seg_flash(idx_seg, SEG_FLASH);
//					
//					//将当前显示值拷贝到tmp8[1~6]。
//					seg_copy_to_tmp(tmp8);		
//					tmp8[0]= ' ';
//					tmp8[7]= '\0';
//					int32_t x= atoi(tmp8);
//					if(4095< x)
//						x= 4095;
//					
//					//设置7760的DA值。
//					dac_out(x*16);	
//				}	
//				else if(KEY_K4_ENTER == key){
//					//保存调整值到FLASH参数区。
//					seg_copy_to_tmp(tmp8);		
//					tmp8[0]= ' ';
//					tmp8[7]= '\0';
//					int32_t x= atoi(tmp8);
//					if(4095< x)
//						x= 4095;
//					
//					uint16_t tmp16= para_self.da20K;
//					para_self.da20K= (uint16_t)x;
//					
//					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
//						uartS("\nsave para_self.da20K");
//					
//						cur_item= cur_item->sibble;	
//						seg_updata(cur_item->content);
//						
//						
//						flag_ma_cal= 0;
//						sta= 0;
//						seg_flash_all(0);
//					}
//					else{		
//						para_self.da20K= tmp16;		//保存失败，恢复旧值（断电完蛋）。
//						
//						seg_flash_all(0);
//						seg_updata("Err00F");
//						
//						uartS("\nerr save para_self.da20K");
//						osDelay(1000);
//					}
//				}
//				else{	
//					
//				}
//				break;
//			
//			default:
//				break;
//		}
//	}
//}



///*先显示i24.000，再修改为实际值。修改时，按OPT键移动光标，按MODE键修改值，按ENTER键保存，ESC键返回。
//*/
//void leaf_Fn_ma_cal_24K(MSG_U msg)
//{
//	static uint8_t sta= 0;
//	static uint8_t idx_seg= 1;	//有效范围：1~6。左起第1个为1。
//	static uint16_t val_change;
//	uint16_t key;
//	char tmp8[8];				//共8B，包含第1个' '（灯状态）和UI的6个字符和1个'\0'。	
//	
//	
//	//输出最大值
//	dac_out(4095*16);
//	
//	if(MSG_TYPE_KEY == msg.type){
//		key= msg.key;
//		
//		switch (sta){
//			case 0:	//显示着"i24000"。
//				if(KEY_K3_MODE == key){
//					//在同级菜单循环切换。
//					cur_item= cur_item->sibble;	
//					seg_updata(cur_item->content);
//				}
//				else if(KEY_K4_ENTER == key){
//					//调整
//					show_val(para_self.mA24K , tmp8);
//					seg_updata(tmp8);
//					set_one_seg_point(3, 1);
//					
//					val_change= para_self.mA24K;
//					
//					flag_ma_cal= 1;
//					osDelay(100);
//					dac_out(4095*16);
//					
//					sta= 1;
//				}
//				else if(KEY_K1_ESC == key){	
//					//返回上级菜单
//					if(cur_item->parent){
//						cur_item= cur_item->parent;	
//						seg_updata(cur_item->content);	
//					}
//					else{
//						uartS("\nerr:no parent");
//					}
//					
//					sta= 0;
//					seg_flash_all(0);
//				}
//				break;
//			
//			case 1:	//显示着实际的电流输出最大值：24.000对应的DA值，通过MODE键调大，OPT键调小，ENTER键盘保存，ESC键返回sta 0并显示"i24000"。
//				if(KEY_K1_ESC == key){
//					//返回状态0。
//					seg_updata("i24000");
//					set_one_seg_point(3, 1);
//					
//					sta= 0;
//					seg_flash_all(0);
//				}
//				else if(key == KEY_K2_OPT){
//					if(0 == strcmp(ITEM_ANA_V_STR, _tbl_ana_out[para_self.ana_out_idx])){
//						inc_one_seg(idx_seg);
//					}
//					else
//						inc_one_seg(idx_seg);
//				}
//				else if(key == KEY_K3_MODE){
//					set_one_seg_flash(idx_seg, SEG_LIGHT);
//					
//					idx_seg++;
//					if(6< idx_seg)
//						idx_seg= 1;
//					set_one_seg_flash(idx_seg, SEG_FLASH);
//				}
//				else if(KEY_K4_ENTER == key){
//					//保存调整值到FLASH参数区。
//					//将当前显示值拷贝到tmp8[1~6]。
//					seg_copy_to_tmp(tmp8);		
//					tmp8[0]= ' ';
//					tmp8[7]= '\0';
//					int32_t x= atoi(tmp8);
//					
//					
//					uint16_t tmp16= para_self.mA24K;
//					para_self.mA24K= (uint16_t)x;
//					
//					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
//						uartS("\nsave para_self.mA24K");
//					
//						cur_item= cur_item->sibble;	
//						seg_updata(cur_item->content);

//						sta= 0;
//						seg_flash_all(0);
//					}
//					else{		
//						para_self.da4K= tmp16;		//保存失败，恢复旧值（断电完蛋）。
//						
//						seg_flash_all(0);
//						seg_updata("Err00F");
//						
//						uartS("\nerr save para_self.mA24K");
//						osDelay(1000);
//					}
//				}
//				else{
//				}
//				break;
//			
//			default:
//				break;
//		}
//	}
//}








/*进入校准流程的叶子菜单项处理函数。即完成密码验证。
*/
void leaf_Fn_cal_in(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	static uint8_t cnt_pass_err= 0;	//密码错误次数，但4次时锁定（只能关电）。
	static char tmp6[8];		//有效范围：1~6.	
	uint16_t key;
	char str_i[7];
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//!!int_menu是全局变量。
				int_menu.dig= 6;		
				int_menu.neg= 0;
				int_menu.val= 0;
				int_menu.max= 999999;
				int_menu.min= 0;
				
				sta= 1;
				sprintf(str_i, "%06d", int_menu.val); 
				seg_updata(str_i);	//测试序列：PASS
				
				//第1个‘0’闪
				int_menu.pos= SEG_L_1;
				x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
				//set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			cnt_pass_err=0;
			
			break;
		case 1:
			//输入密码：按opt键调值，按mode键移位，按Enter键进行密码确认，按Esc键无效。
			if(key == KEY_K2_OPT){
				int_menu_inc_one_seg(0);	//x_seg_inc_one(int_menu.pos);
			}
			else if(key == KEY_K3_MODE){
				int_menu_change_pos();
//				x_seg_one_flash(int_menu.pos, DISP_X_MODE_NORM); 	//停止当前位置的数码管闪。set_one_seg_flash(idx_seg, SEG_LIGHT);	
//				
//				int_menu.pos++;
//				if(SEG_L_6< int_menu.pos)
//					int_menu.pos= SEG_L_1;
//				x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
			}
			else if(key == KEY_K4_ENTER){
				sprintf(tmp6, "%06d", int_menu.val);
				//x_seg_copy_to_tmp(tmp6);		//seg_copy_to_tmp(tmp6);
				
				//比较密码，如果正确，进入下一个邻居菜单。
				if(0UL == pass_compare(tmp6)){
					sta= 0;
					
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	//cur_item->f_enter();
					
					x_seg_one_flash(int_menu.pos, DISP_X_MODE_ON);	//关闭闪烁
				}
				else{
					cnt_pass_err++;
					//否则，显示Error为1秒。
					x_seg_copy_to_tmp(tmp6);	//seg_copy_to_tmp(tmp6);
					x_seg_one_flash(int_menu.pos, DISP_X_MODE_ON);	//关闭闪烁
					
					if(1 == cnt_pass_err)
						seg_updata("Error1");
					else if(2 == cnt_pass_err)
						seg_updata("Error2");
					else if(3 == cnt_pass_err)
						seg_updata("Error3");
					else if(4 == cnt_pass_err){
						seg_updata("Error4");
						while(1);
					}
					osDelay(2000);
					
					
					int_menu.dig= 6;		
					int_menu.neg= 0;
					int_menu.val= 0;
					
					sta= 1;
					sprintf(str_i, "%06d", int_menu.val); 
					seg_updata(str_i);	//测试序列：PASS
					
					//第1个‘0’闪
					int_menu.pos= SEG_L_1;
					x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
				}
			}
			else{
				//不处理
			}
			
			break;
		default:
			break;
	}
	

}	

/*小数点位置叶子菜单项处理函数。
带有状态的（sta）。
从pt开始，经1d,cp,t,load1器件不能退出，之后的load2,load3,load4,sen,siocal和pass可以退出。
*/
void leaf_Fn_cal_pt(MSG_U msg)
{
	static uint8_t sta= 0;
//	static uint8_t idx_seg= 1;	//有效范围：1~6
	static  uint8_t pos;		//小数点位置。
	char tmp8[8];
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:	
			if(KEY_K4_ENTER == key){
				//读取当前小数点，并显示。
				pos= para_xxx.pt_pos_idx;
				
				show_pt(pos, tmp8);
				seg_updata(tmp8);
				
				set_one_seg_point(6-pos, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
				
				sta= 1;
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT键调整数值，按Enter确认并进入同级下一个菜单。
			if(key == KEY_K2_OPT){
				pos++;
				pos%=5;	//0,1,2,3,4.
				
				//重新显示小数点位置。
				show_pt(pos, tmp8);
				seg_updata(tmp8);
				
				set_one_seg_point(6-pos, 1);
			}
			else if(KEY_K3_MODE == key){
				if(0 == pos)
					pos= 4;
				else
					pos--;

				pos%=5;	//0,1,2,3,4.
				
				//重新显示小数点位置。
				show_pt(pos, tmp8);
				seg_updata(tmp8);
				
				set_one_seg_point(6-pos, 1);
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.pt_pos_idx;
				para_xxx.pt_pos_idx= pos;
				
								
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.pos_dot");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{		
					para_xxx.pt_pos_idx= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.pos_dot");
					osDelay(1000);
				}
			}
			
			break;
		
		default:
			break;
	}		
}



/*分度值叶子菜单项处理函数。1d不是Ld。
分度值：1/2/5/10/20/50。索引：0，1，2，3，4，5。有些麻烦啊，索引---真实值
*/
void leaf_Fn_cal_1d(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint16_t val_change= 1;	//有效范围：[0, 5] -> 1/2/5/10/20/50.
	char tmp8[8];
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			if(KEY_K4_ENTER == key){
				//读取现有分度值并闪显。
				val_change= 0;	//默认值（若未在_tbl_int_fd[]中找到，也是这个值）
				for(int i= 0; i<6; i++){
					if(para_xxx.fd_min == _tbl_int_fd[i]){
						val_change= i;
						break;
					}
				}
				
				show_1d(val_change, tmp8);
				seg_updata(tmp8);
				
				set_one_seg_flash(5, SEG_FLASH);
				set_one_seg_flash(6, SEG_FLASH);
				
				sta= 1;
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				uartS("\nesc ld");
				
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
			
		case 1:
			//按OPT选择分度值，按Enter键设置，并进入下一个同级菜单。
			if(KEY_K2_OPT == key){
				//调整分度值。
				if(0 == val_change)
					val_change= 5;
				else
					val_change--;
				
				show_1d(val_change, tmp8);
				seg_updata(tmp8);
			}
			else if(KEY_K3_MODE == key){
				//调整分度值。
				if(5<= val_change)
					val_change= 0;
				else
					val_change++;

				show_1d(val_change, tmp8);
				seg_updata(tmp8);	
			}
			else if(KEY_K4_ENTER == key){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.fd_min;
				para_xxx.fd_min= _tbl_int_fd[val_change];
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.fd_min");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_xxx.fd_min= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.fd_min");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				//不保存当前分度值，在同级菜单循环切换？
				uartS("\nesc para_xxx.fd_min");
				
				seg_updata(cur_item->content);

				sta= 0;
				seg_flash_all(0);
			}
			break;
			
		default:
			break;
	}			

}



/*最大量程叶子菜单项处理函数。
!!按当前的pt值显示。
*/
void leaf_Fn_cal_cp(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t idx_seg= 1;	//有效范围：1~6
	char tmp8[8];				//
	char str_i[7];
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:	
			if(KEY_K4_ENTER == key){
				//进入最大量程设置，并显示“100000”。!!不读取当前量程。
				if(fs_max> 999999)
					fs_max= 0;
				if(fs_max< -99999)
					fs_max= 0;
				
				//!!int_menu是全局变量。
				int_menu.dig= 6;		
				int_menu.neg= 0;
				int_menu.val= fs_max;
				int_menu.max= 999999;
				int_menu.min= 0;
				
				sta= 1;
				sprintf(str_i, "%06d", int_menu.val); 
				seg_updata(str_i);	//测试序列：PASS
				
				//第1个‘0’闪
				int_menu.pos= SEG_L_1;
				x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
				x_seg_set_point(5- para_xxx.pt_pos_idx, 1);		//显示小数点
				
				sta= 1;
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
			
			break;
			
		case 1:
			//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
			if(key == KEY_K2_OPT){
				int_menu_inc_one_seg(0);	//x_seg_inc_one(int_menu.pos);
				x_seg_set_point(5- para_xxx.pt_pos_idx, 1);
			}
			else if(key == KEY_K3_MODE){
				int_menu_change_pos();
//				x_seg_one_flash(int_menu.pos, DISP_X_MODE_NORM); 	//停止当前位置的数码管闪。set_one_seg_flash(idx_seg, SEG_LIGHT);	
//				
//				int_menu.pos++;
//				if(SEG_L_6< int_menu.pos)
//					int_menu.pos= SEG_L_1;
//				x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
			}
			else if(key == KEY_K4_ENTER){
				//保存旧值。
				uint16_t val_tmp16= para_xxx.fs_max_hi;
				uint16_t val_tmp16_2= para_xxx.fs_max_lo;
				
				//x_seg_copy_to_tmp(tmp8);	//seg_copy_to_tmp(pass1);
				x_seg_flash_all(0);			//关闭闪烁
				
//				tmp8[7]= '\0';
//				uint32_t cp= atoi(tmp8);
				para_xxx.fs_max_hi= int_menu.val>> 16;
				para_xxx.fs_max_lo= (uint16_t)int_menu.val;
				
								
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
					uartS("\nsave para_xxx.fs_max_hi/lo");
					
					update_fs_max();		//更新二次参数。
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					x_seg_flash_all(0);
					x_seg_set_point(5- para_xxx.pt_pos_idx, 0);
				}
				else{	
					val_tmp16= para_xxx.fs_max_hi= val_tmp16;		//保存失败，恢复旧值（断电完蛋）。
					val_tmp16_2= para_xxx.fs_max_lo= val_tmp16_2;	
					
					x_seg_flash_all(0);
					x_seg_set_point(5- para_xxx.pt_pos_idx, 0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_xxx.fs_max_hi/lo");
					osDelay(1000);
				}
			}
			else if(KEY_K1_ESC == key){
				sta= 0;
				
				seg_updata(cur_item->content);
				x_seg_flash_all(0);
				x_seg_set_point(5- para_xxx.pt_pos_idx, 0);
			}
			
			break;
		
		default:
			break;
	}			
}



/*标定零点叶子菜单项处理函数。
!!显示当前的mv值。（第1个数码管显示t，不可被覆盖）。
在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
从pt开始，经1d,cp,t,load1器件不能退出，之后的load2,load3,load4,sen,siocal和pass可以退出。
*/
void leaf_Fn_cal_t(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t disp_mv= 0;		//是否显示mv值。
	static int32_t ad;				//和uV伴随而来的ad值。
	static int32_t uv;				//和ad伴随而来的uv值。
	static int32_t uv_man= -999999;	//默认为-999999，不是手动输入mv值。
	uint16_t key;
	char tmp8[8];
	char str_i[7];
	char str[32];
	
	if(msg.type == MSG_TYPE_KEY){
		key= msg.key;
		
		switch (sta){
			case 0:	
				if(KEY_K4_ENTER == key){
					disp_mv= 1;	//按Enter键，以允许显示mv值。
					mode_mv_wt= MODE_MV;
					
					sta= 1;
					
					//准备调整校准过程中的滤波强度。
					flag_para_update_fir= 'C';
					
					//显示
					x_disp_now("     0", 0x20, LED_ALL);
					//x_seg_flash_all(1);
				}
				else if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	
				}
				else if(KEY_K1_ESC == key){
					//返回上一级菜单。
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);
				}
				
				break;
				
			case 1://动态显示mv值，可切换到手动输入mv值。
				//按Enter确认并进入同级下一个菜单。
				if(key == KEY_K2_OPT){	//进入手动零点标定流程
					//seg_updata(cur_item->content);
					//!!int_menu是全局变量。
					int_menu.dig= 6;		
					int_menu.neg= 1;	//允许负值。
					int_menu.val= 0;
					int_menu.max= 999999;
					int_menu.min= -99999;
					
					sta= 1;
					sprintf(str_i, "%06d", int_menu.val); 
					seg_updata(str_i);	//测试序列：PASS
					
					//第1个‘0’闪
					int_menu.pos= SEG_L_1;
					x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
					x_seg_set_point(PT_L_3, 1);
					
					sta= 3;			//跳到”手动输入mv值”。
					disp_mv= 0;		//
				}
				else if(key == KEY_K4_ENTER){
					
					//需要判断当前STAB为1才能保存，否则什么也不做。			
					if(stab_arr.mv_stab){
						disp_mv= 0;	//停止动态显示
						
						//保存当前mv值。	
						cal_ctx.pt[0].uv= uv;
					
												
						//sta= 1;
						sprintf(str_i, "%06d", uv); 
						str_i[0]='o';
						seg_updata(str_i);	//显示形如"oNN.NNN"的mv值。
						x_seg_set_point(PT_L_3, 3);
										
						sta= 2;
					}
				}		
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//准备恢复校准过程中的滤波强度。
					flag_para_update_fir= 'X';
					
					x_seg_set_point(SEG_L_3, 0);
				}
				
				break;
				
			case 2:	//执行标定或取消。现在和DT45接近了：零点需要2次确认（于洪说的）。
				if(key == KEY_K4_ENTER){	//按Enter确认并进入同级下一个菜单。	
					//保存旧值。
					CAL_CTX cal_ctx_bk;

					cal_save_to_pt(&cal_ctx_bk);

										
					cal_ctx.pt[0].ad= ad;		
					cal_ctx.pt[0].uv= uv;
					cal_ctx.pt[0].load= 0;	
					cal_ctx.pt[0].cap_cal= fs_max;										//保存表示是的量程。量程可变。
					cal_ctx.pt[0].div_cal= para_xxx.fd_min;								//保存标定时的分度值，无屌用。
					
					cal_ctx.pt[0].k= 9.12345678F;		//固定为9.12345678F，看看float表达为什么，输出显示“9.123457”。
					
					if(-999999 != uv_man){
						//使用手动输入值
						cal_ctx.pt[0].ad= mv_to_ad(uv_man);
						cal_ctx.pt[0].uv= uv_man;
						cal_ctx.pt[0].used= 1;
									
						sprintf(str, "\n\nLoad%d manual", cur_item->id);
						uartS(str);
					}
					
					//（重新）标定零点对加载点的影响。只简单平移ad，不重新计算load。
					//TODO需要知道ad的变化量=new-old= pt[0].ad- pt.ad。
					cal_update_ad(ad- cal_ctx_bk.pt[0].ad);	//更新所有加载点对应的ad值。
					
					
					//零点时，不再复位加载点，以实现单独标定各个点功能。					
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_CAL)){
						uartS("\nsave load 0");
						
						x_disp_now("DONE  ", 0x20, LED_ALL);
						x_seg_flash_all(0);
						
						sta= 2;	
						disp_mv= 0;					//停止动态显示	

						offset_clear();
					}
					else{		
						cal_restore_from_pt(&cal_ctx_bk);
						
						x_seg_flash_all(0);
						x_disp_now("Err00F", 0x20, LED_ALL);
						
						uartS("\n$err save load 0");
						osDelay(1000);
					}
					
					//切换到下一个菜单项。
					cur_item= cur_item->sibble;
					seg_updata(cur_item->content);
						
					sta= 0;
					disp_mv= 0;
					
					//准备恢复校准过程中的滤波强度。
					flag_para_update_fir= 'X';
					
					x_seg_set_point(SEG_L_3, 0);
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					
					//准备恢复校准过程中的滤波强度。
					flag_para_update_fir= 'X';
					
					x_seg_set_point(SEG_L_3, 0);
				}

				break;
				
			case 3:	//手动输入mv值。
				if(key == KEY_K1_ESC){
				}
				else if(key == KEY_K2_OPT){
					int_menu_inc_one_seg(0);	//x_seg_inc_one(int_menu.pos);
					x_seg_set_point(SEG_L_3, 1);
				}
				else if(key == KEY_K3_MODE){
					int_menu_change_pos();
					x_seg_set_point(SEG_L_3, 1);
				}
				else if(key == KEY_K4_ENTER){
					uv_man= int_menu.val;		//实际mv值是输入值+零点mv值。
					
					x_seg_set_point(SEG_L_3, 1);
					x_seg_flash_all(0);
				
					sprintf(str_i, "%06d", uv_man); 
					str_i[0]='o';
					seg_updata(str_i);
								
					sta= 2;
				}
				
				break;
				
			
			default:
				break;
		}
	}
	else if(msg.type == MSG_TYPE_MV_WT){
		char str[32];
		char str_x[16];
		
		if(disp_mv){
			//显示mv值。
//			seg_mv_to_seg(msg.uv, msg.dat[0]);
//			set_one_seg(1,'C',0);
			
			ad= msg.ad;
			uv= msg.uv;
			uv_man= -999999;
			
			sprintf(str_x, "%06d", uv);
			if(0 == stab_arr.mv_stab)
				x_disp_now(str_x, 0, LED_STAB_BIT);
			else
				x_disp_now(str_x, LED_STAB_BIT, LED_STAB_BIT);
			
			x_seg_set_point(SEG_L_3, 1);
			
			sprintf(str, "\nmv:ad=%d, uv=%d, mvs=%d",ad, uv, stab_arr.mv_stab);
			uartS(str);
		}		
	}
}



/*标定第n(0<n)点叶子菜单项处理函数。
先显示LoAdn，确定后显示"Add Ld"约1秒后，显示mv值。再确定，如果此时STAB有效，则进入设置标定1的称重值；无效（不稳）则死等。QQ如何退出死等状态？
在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
*/
void leaf_Fn_cal_load_n(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t disp_mv= 0;		//是否显示mv值。
	static int32_t ad;				//和uV伴随而来的ad值。
	static int32_t uv;				//和ad伴随而来的uv值。
	static int32_t uv_man= -999999;	//默认为-999999，不是手动输入mv值。
	uint16_t key;
	char tmp8[8];
	char str_i[7];
	char str[32];
	
	if(msg.type == MSG_TYPE_KEY){
		key= msg.key;
		
		switch (sta){
			case 0:	//初始：设置滤波标志，设置disp_mv。
				if(KEY_K4_ENTER == key){
					seg_updata("Add Ld");
					osDelay(1000);
					
					disp_mv=1;
					mode_mv_wt= MODE_MV;
					
					sta= 1;
					
					//准备调整校准过程中的滤波强度。
					flag_para_update_fir= 'C';
				}
				else if(KEY_K3_MODE == key){
					//在同级菜单循环切换。
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	
				}
				else if(KEY_K1_ESC == key){
					//返回上一级菜单。
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);
					
					x_seg_set_point(SEG_L_3, 0);
				}
		
				break;
				
			case 1://动态显示当前mv值。
				if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					seg_updata(cur_item->content);
					x_seg_set_point(5- para_xxx.pt_pos_idx, 0);	
					
					
					//滤波强度要恢复。
					flag_para_update_fir= 'X';
				}
				else if(key == KEY_K2_OPT){
					//
					//!!int_menu是全局变量。
					int_menu.dig= 6;		
					int_menu.neg= 1;	//允许负值。
					int_menu.val= 0;
					int_menu.max= 999999;
					int_menu.min= -99999;
					
					sta= 1;
					sprintf(str_i, "%06d", int_menu.val); 
					seg_updata(str_i);
				
					//idx_flash= SEG_L_1;
					x_seg_flash_all(0);
					int_menu.pos= SEG_L_1;
					x_seg_one_flash(int_menu.pos,DISP_X_MODE_FF);
					x_seg_set_point(PT_L_3, 1);	
					
					sta= 3;
					disp_mv= 0;	//不再使用底层送上来的mv值。
				}
				else if(key == KEY_K4_ENTER){
					
					//需要判断当前STAB为1才能保存，否则什么也不做。			
					if(stab_arr.mv_stab){
						disp_mv= 0;	//停止动态显示
						
						//保存当前mv值。	
						cal_ctx.pt[cur_item->id].uv= uv;
					
						//
						//!!int_menu是全局变量。
						int_menu.dig= 6;		
						int_menu.neg= 0;
						int_menu.val= 0;
						
						//sta= 1;
						sprintf(str_i, "%06d", int_menu.val); 
						seg_updata(str_i);	//测试序列：PASS
					
						int_menu.pos= SEG_L_1;
						x_seg_one_flash(int_menu.pos,DISP_X_MODE_FF); 
						x_seg_set_point(5- para_xxx.pt_pos_idx, 1);		
						
						sta= 2;
					}
				}
				
				break;
				
			case 2:	//手动输入称重值，并计算k后保存。
				//按opt键调值，按mode键移位，按Enter键进行密码确认，按Esc键无效。
				if(key == KEY_K2_OPT){
					int_menu_inc_one_seg(0);	//x_seg_inc_one(int_menu.pos);
					x_seg_set_point(5- para_xxx.pt_pos_idx, 1);
				}
				else if(key == KEY_K3_MODE){
					int_menu_change_pos();
					x_seg_set_point(5- para_xxx.pt_pos_idx, 1);
				}
				else if(key == KEY_K4_ENTER){
					x_seg_flash_all(0);			//关闭闪烁
					
					//保存旧值。
					if(4< cur_item->id){
						sprintf(str, "\n$err load %d", cur_item->id);
						uartS(str);
						break;
					}
					
					CAL_CTX cal_ctx_bk;
					
					cal_save_to_pt(&cal_ctx_bk);
					
					/*计算k
					*/		
					cal_ctx.pt[cur_item->id].uv= uv;	//当前实时上报的uv,ad。
					cal_ctx.pt[cur_item->id].ad= ad;
					cal_ctx.pt[cur_item->id].used= 1;
					cal_ctx.pt[cur_item->id].load= int_menu.val;
					cal_ctx.pt[cur_item->id].cap_cal= fs_max;				//保存标定时的量程。量程可变，但此值不变。
					cal_ctx.pt[cur_item->id].div_cal= para_xxx.fd_min;		//标定时的分度值。分度值可变，但此值不变。
					cal_ctx.pt[cur_item->id].div_cnt= (int32_t)(cal_ctx.pt[cur_item->id].load/cal_ctx.pt[cur_item->id].div_cal+ 0.5);	//.div_cnt是一个整数。
					

					
					if(-999999 != uv_man){
						//使用手动输入值
						cal_ctx.pt[cur_item->id].uv= uv_man;				//相对mv值。
						cal_ctx.pt[cur_item->id].ad= mv_to_ad(uv_man+ cal_ctx.pt[0].uv);
						cal_ctx.pt[cur_item->id].used= 1;
									
						sprintf(str, "\n\nLoad%d manual", cur_item->id);
						uartS(str);
					}
					
					if(0 == (cal_ctx.pt[cur_item->id].load- cal_ctx.pt[cur_item->id- 1].load)){
						cal_restore_from_pt(&cal_ctx_bk);
						
						//直接报错退出。
						seg_updata("Err00F");
						
						uartS("\n$err save load 1");
						osDelay(1000);
						
						return;
					}
					
					cal_ctx.pt[cur_item->id].k= (cal_ctx.pt[cur_item->id].ad-cal_ctx.pt[cur_item->id- 1].ad);
					cal_ctx.pt[cur_item->id].k/=(float)(cal_ctx.pt[cur_item->id].load- cal_ctx.pt[cur_item->id- 1].load);		//!!!必须先强制转换为float，否则值由2601.699951变为2601.000000。
					
					//将本加载点的值拷贝到之后的所有加载点。
					cal_update_other_load(cur_item->id);
					
									
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_CAL)){
						char str[128];
						sprintf(str, "\n$ok save load%d= %d, ad=%d, cap_cal=%d,div_cal=%f, k=%f", cur_item->id, cal_ctx.pt[cur_item->id].load, cal_ctx.pt[cur_item->id].ad, cal_ctx.pt[cur_item->id].cap_cal, cal_ctx.pt[cur_item->id].div_cal, cal_ctx.pt[cur_item->id].k); 
						uartS(str);
					
						cur_item= cur_item->sibble;	
						seg_updata(cur_item->content);

						sta= 0;
						x_seg_flash_all(0);
						
						
						//准备恢复校准过程中的滤波强度。
						//flag_para_update_fir= 'X';
					}
					else{		
						//保存失败，恢复旧值（断电完蛋）。
						cal_restore_from_pt(&cal_ctx_bk);
						
						seg_flash_all(0);
						seg_updata("Err00F");
						
						sprintf(str, "\n$err load %d", cur_item->id);
						uartS(str);
						osDelay(1000);
					}
				}
				else if(key == KEY_K1_ESC){
					sta= 0;
					disp_mv= 0;
					
					x_seg_flash_all(0);
					seg_updata(cur_item->content);
					x_seg_set_point(5- para_xxx.pt_pos_idx, 0);
					
					//准备恢复校准过程中的滤波强度。
					flag_para_update_fir= 'X';
				}
				
				break;
				
			case 3:	//手动输入mv值。
				if(key == KEY_K1_ESC){
				}
				else if(key == KEY_K2_OPT){
					int_menu_inc_one_seg(0);	//x_seg_inc_one(int_menu.pos);
					x_seg_set_point(SEG_L_3, 1);
				}
				else if(key == KEY_K3_MODE){
					int_menu_change_pos();
					x_seg_set_point(SEG_L_3, 1);
				}
				else if(key == KEY_K4_ENTER){
					uv_man= int_menu.val;		//实际mv值是输入值+零点mv值。
					
					x_seg_set_point(SEG_L_3, 0);
					x_seg_flash_all(0);
					
					
					//准备跳到标定，即输入称重值。
					//!!int_menu是全局变量。
					int_menu.dig= 6;		
					int_menu.neg= 0;
					int_menu.val= 0;
					int_menu.pos= SEG_L_1;
					
					sta= 1;
					sprintf(str_i, "%06d", int_menu.val); 	
					seg_updata(str_i);
				
					//idx_flash= SEG_L_1;
					x_seg_one_flash(SEG_L_1, DISP_X_MODE_FF); 
					x_seg_set_point(5- para_xxx.pt_pos_idx, 1);	
					
					sta= 2;
				}
				
				break;
				
			default:
				break;
		}
	}
	else if(msg.type == MSG_TYPE_MV_WT){
		char str[32];
		char str_x[16];
		
		if(disp_mv){
			//显示mv值。
			ad= msg.ad;
			//uv= msg.uv;					//显示实际毫伏值。
			uv= msg.uv- cal_ctx.pt[0].uv;	//显示差值=实际毫伏值-零点毫伏值。
			uv_man= -999999;
			
			sprintf(str_x, "%06d", uv);
			if(0 == stab_arr.mv_stab)
				x_disp_now(str_x, 0, LED_STAB_BIT);
			else
				x_disp_now(str_x, LED_STAB_BIT, LED_STAB_BIT);
			
			x_seg_set_point(SEG_L_3, 1);
			
			sprintf(str, "\nmv:ad=%d, uv=%d, mvs=%d",ad, uv, stab_arr.mv_stab);
			uartS(str);
		}		
	}
}



///*标定第1点叶子菜单项处理函数。
//先显示LoAD1，确定后显示"Add ld"约1秒后，显示mv值。再确定，如果此时STAB有效，则进入设置标定1的称重值；无效（不稳）则死等。QQ如何退出死等状态？
//在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
//*/
//void leaf_Fn_cal_load1(MSG_U msg)
//{
//	static uint8_t sta= 0;
//	static uint8_t idx_flash= 1;	//有效范围：1~6
//	static uint8_t disp_mv= 0;		//是否显示mv值。
//	static int32_t ad;				//和uV伴随而来的ad值。
//	uint16_t key;
//	char tmp8[8];
//	
//	
//	if(msg.type == MSG_TYPE_KEY){
//		key= msg.key;
//		
//		switch (sta){
//			case 0:	
//				if(KEY_K4_ENTER == key){
//					seg_updata("Add ld ");
//					osDelay(1000);
//					
//					disp_mv=1;
//					mode_mv_wt= MODE_MV;
//					
//					sta= 1;
//					
//					//准备调整校准过程中的滤波强度。
//					flag_para_update_fir= 'C';
//				}
//				else if(KEY_K3_MODE == key){
//					//在同级菜单循环切换。
//					cur_item= cur_item->sibble;	
//					seg_updata(cur_item->content);	
//				}
//				else if(KEY_K1_ESC == key){
//					//返回上一级菜单。
//					cur_item= cur_item->parent;	
//					seg_updata(cur_item->content);
//				}
//		
//				break;
//				
//			case 1:
//				if(key == KEY_K4_ENTER){
//					
//					//需要判断当前STAB为1才能保存，否则什么也不做。
//					if(seg_stab_sta()){
//						disp_mv= 0;	//停止动态显示
//						
//						//保存当前mv值。
//						seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
//					
//						tmp8[0]= ' ';
//						if('C' == tmp8[1])
//							tmp8[1]= ' ';			//去掉第1个数码管的'C'。
//						tmp8[7]='\0';
//						point[1].uv= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
//						
//					
//						//
//						seg_updata("000000 ");
//						idx_flash= 1;
//						set_one_seg_flash(idx_flash, SEG_FLASH);
//						set_one_seg_point(6-para_xxx.pt_pos_idx, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
//						
//						sta= 2;
//					}
//				}
//				else if(key == KEY_K1_ESC){
//					sta= 0;
//					disp_mv= 0;
//					
//					seg_updata(cur_item->content);
//					
//					//滤波强度要恢复。
//					flag_para_update_fir= 'X';
//				}
//				
//				break;
//				
//			case 2:
//				//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
//				if(key == KEY_K2_OPT){
//					inc_one_seg(idx_flash);
//				}
//				else if(key == KEY_K3_MODE){
//					set_one_seg_flash(idx_flash, SEG_LIGHT);
//					
//					idx_flash++;
//					if(6< idx_flash)
//						idx_flash= 1;
//					set_one_seg_flash(idx_flash, SEG_FLASH);
//				}
//				else if(key == KEY_K4_ENTER){
//					//保存旧值。
//					POINT pt;
//					pt.load= point[1].load;
//					pt.ad= point[1].ad;
//					pt.used= point[1].used;
//					
//					seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
//					
//					tmp8[0]= ' ';
//					if('C' == tmp8[1])
//						tmp8[1]= ' ';			//去掉第1个数码管的'C'。
//					tmp8[7]='\0';
//					point[1].load= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
//					point[1].ad= ad;
//					point[1].used= 1;
//					
//									
//					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
//						uartS("\nsave load 1");
//					
//						cur_item= cur_item->sibble;	
//						seg_updata(cur_item->content);

//						sta= 0;
//						seg_flash_all(0);
//						
//						
//						//准备恢复校准过程中的滤波强度。
//						flag_para_update_fir= 'X';
//					}
//					else{		
//						point[1].load= pt.load;		//保存失败，恢复旧值（断电完蛋）。
//						point[1].ad= pt.ad;
//						point[1].used= pt.used;
//						
//						seg_flash_all(0);
//						seg_updata("Err00F");
//						
//						uartS("\nerr save load 1");
//						osDelay(1000);
//					}
//				}
//				else if(key == KEY_K1_ESC){
//					sta= 0;
//					disp_mv= 0;
//					
//					seg_updata(cur_item->content);
//					
//					//准备恢复校准过程中的滤波强度。
//					flag_para_update_fir= 'X';
//				}
//				
//				break;				
//			
//			default:
//				break;
//		}
//	}
//	else if(msg.type == MSG_TYPE_MV_WT){
//		uartS("\nmv");
//		if(disp_mv){
//			//显示mv值。
//			seg_mv_to_seg(msg.uv, msg.dat[0]);
//			set_one_seg(1,'C',0);
//			
//			ad= msg.ad;
//		}	
//	}
//}






///*标定第2点叶子菜单项处理函数。
//先显示LoAD2，确定后显示"Add ld"约1秒后，显示mv值。再确定，如果此时STAB有效，则进入设置标定2的称重值；无效（不稳）则死等。QQ如何退出死等状态？
//在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
//*/
//void leaf_Fn_cal_load2(MSG_U msg)
//{
//	static uint8_t sta= 0;
//	static uint8_t idx_flash= 1;	//有效范围：1~6
//	static uint8_t disp_mv= 0;		//是否显示mv值。
//	static int32_t ad;				//和uV伴随而来的ad值。
//	uint16_t key;	
//	char tmp8[8];
//	
//	
//	if(msg.type == MSG_TYPE_KEY){
//		key= msg.key;
//		
//		switch (sta){
//			case 0:	
//				if(KEY_K4_ENTER == key){
//					seg_updata("Add ld ");
//					osDelay(1000);
//					
//					disp_mv=1;
//					mode_mv_wt= MODE_MV;
//					
//					sta= 1;
//					
//					//准备调整校准过程中的滤波强度。
//					flag_para_update_fir= 'C';
//				}
//				else if(KEY_K3_MODE == key){
//					//在同级菜单循环切换。
//					cur_item= cur_item->sibble;	
//					seg_updata(cur_item->content);	
//				}
//				else if(KEY_K1_ESC == key){
//					//返回上一级菜单。
//					cur_item= cur_item->parent;	
//					seg_updata(cur_item->content);
//				}
//				
//				break;
//				
//			case 1:
//				if(key == KEY_K4_ENTER){
//					
//					//需要判断当前STAB为1才能保存，否则什么也不做。
//					if(seg_stab_sta()){
//						disp_mv= 0;	//停止动态显示
//						
//						//保存当前mv值。
//						seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
//					
//						tmp8[0]= ' ';
//						if('C' == tmp8[1])
//							tmp8[1]= ' ';			//去掉第1个数码管的'C'。
//						tmp8[7]='\0';
//						point[2].uv= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
//						
//						
//						//
//						seg_updata("000000 ");
//						idx_flash= 1;
//						set_one_seg_flash(idx_flash, SEG_FLASH);
//						set_one_seg_point(6-para_xxx.pt_pos_idx, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
//						
//						sta= 2;
//					}
//				}
//				else if(key == KEY_K1_ESC){
//					sta= 0;
//					disp_mv= 0;
//					
//					seg_updata(cur_item->content);
//					
//					//滤波强度要恢复。
//					flag_para_update_fir= 'X';
//				}
//				
//				break;
//				
//			case 2:
//				//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
//				if(key == KEY_K2_OPT){
//					inc_one_seg(idx_flash);
//				}
//				else if(key == KEY_K3_MODE){
//					set_one_seg_flash(idx_flash, SEG_LIGHT);
//					
//					idx_flash++;
//					if(6< idx_flash)
//						idx_flash= 1;
//					set_one_seg_flash(idx_flash, SEG_FLASH);
//				}
//				else if(key == KEY_K4_ENTER){
//					//保存旧值。
//					POINT pt;
//					pt.load= point[2].load;
//					pt.ad= point[2].ad;
//					pt.used= point[2].used;
//					
//					seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
//					
//					tmp8[0]= ' ';
//					if('C' == tmp8[1])
//						tmp8[1]= ' ';			//去掉第1个数码管的'C'。
//					tmp8[7]='\0';
//					point[2].load= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
//					point[2].ad= ad;
//					point[2].used= 1;
//					
//									
//					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
//						uartS("\nsave load 2");
//					
//						cur_item= cur_item->sibble;	
//						seg_updata(cur_item->content);

//						sta= 0;
//						seg_flash_all(0);
//						
//						//准备恢复校准过程中的滤波强度。
//						flag_para_update_fir= 'X';
//					}
//					else{		
//						point[2].load= pt.load;		//保存失败，恢复旧值（断电完蛋）。
//						point[2].ad= pt.ad;
//						point[2].used= pt.used;
//						
//						seg_flash_all(0);
//						seg_updata("Err00F");
//						
//						uartS("\nerr save load 2");
//						osDelay(1000);
//					}
//				}
//				else if(key == KEY_K1_ESC){
//					sta= 0;
//					disp_mv= 0;
//					
//					seg_updata(cur_item->content);
//					
//					//准备恢复校准过程中的滤波强度。
//					flag_para_update_fir= 'X';
//				}
//				
//				break;				
//			
//			default:
//				break;
//		}
//	}
//	else if(msg.type == MSG_TYPE_MV_WT){
//		uartS("\nmv");
//		if(disp_mv){
//			//显示mv值。
//			seg_mv_to_seg(msg.uv, msg.dat[0]);
//			set_one_seg(1,'C',0);
//						
//			ad= msg.ad;
//		}	
//	}
//}




///*标定第3点叶子菜单项处理函数。
//先显示LoAD3，确定后显示"Add ld"约1秒后，显示mv值。再确定，如果此时STAB有效，则进入设置标定3的称重值；无效（不稳）则死等。QQ如何退出死等状态？
//在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
//*/
//void leaf_Fn_cal_load3(MSG_U msg)
//{
//	static uint8_t sta= 0;
//	static uint8_t idx_flash= 1;	//有效范围：1~6
//	static uint8_t disp_mv= 0;		//是否显示mv值。
//	static int32_t ad;				//和uV伴随而来的ad值。
//	uint16_t key;	
//	char tmp8[8];
//	
//	
//	if(msg.type == MSG_TYPE_KEY){
//		key= msg.key;
//		
//		switch (sta){
//			case 0:	
//				if(KEY_K4_ENTER == key){
//					seg_updata("Add ld ");
//					osDelay(1000);
//					
//					disp_mv=1;
//					mode_mv_wt= MODE_MV;
//					
//					sta= 1;
//					
//					//准备调整校准过程中的滤波强度。
//					flag_para_update_fir= 'C';
//				}
//				else if(KEY_K3_MODE == key){
//					//在同级菜单循环切换。
//					cur_item= cur_item->sibble;	
//					seg_updata(cur_item->content);	
//				}
//				else if(KEY_K1_ESC == key){
//					//返回上一级菜单。
//					cur_item= cur_item->parent;	
//					seg_updata(cur_item->content);
//				}
//				
//				break;
//				
//			case 1:
//				if(key == KEY_K4_ENTER){
//					
//					//需要判断当前STAB为1才能保存，否则什么也不做。
//					if(seg_stab_sta()){
//						
//						disp_mv= 0;	//停止动态显示
//						
//						//保存当前mv值。
//						seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
//					
//						tmp8[0]= ' ';
//						if('C' == tmp8[1])
//							tmp8[1]= ' ';			//去掉第1个数码管的'C'。
//						tmp8[7]='\0';
//						point[3].uv= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
//						
//						
//						//
//						seg_updata("000000 ");
//						idx_flash= 1;
//						set_one_seg_flash(idx_flash, SEG_FLASH);
//						set_one_seg_point(6-para_xxx.pt_pos_idx, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
//						
//						sta= 2;
//					}
//				}
//				else if(key == KEY_K1_ESC){
//					sta= 0;
//					disp_mv= 0;
//					
//					seg_updata(cur_item->content);
//					
//					//滤波强度要恢复。
//					flag_para_update_fir= 'X';
//				}
//				
//				break;
//				
//			case 2:
//				//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
//				if(key == KEY_K2_OPT){
//					inc_one_seg(idx_flash);
//				}
//				else if(key == KEY_K3_MODE){
//					set_one_seg_flash(idx_flash, SEG_LIGHT);
//					
//					idx_flash++;
//					if(6< idx_flash)
//						idx_flash= 1;
//					set_one_seg_flash(idx_flash, SEG_FLASH);
//				}
//				else if(key == KEY_K4_ENTER){
//					//保存旧值。
//					POINT pt;
//					pt.load= point[3].load;
//					pt.ad= point[3].ad;
//					pt.used= point[3].used;
//					
//					seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
//					
//					tmp8[0]= ' ';
//					if('C' == tmp8[1])
//						tmp8[1]= ' ';			//去掉第1个数码管的'C'。
//					tmp8[7]='\0';
//					point[3].load= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
//					point[3].ad= ad;
//					point[3].used= 1;
//					
//									
//					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
//						uartS("\nsave load 3");
//					
//						cur_item= cur_item->sibble;	
//						seg_updata(cur_item->content);

//						sta= 0;
//						seg_flash_all(0);
//						
//						//准备恢复校准过程中的滤波强度。
//						flag_para_update_fir= 'X';
//					}
//					else{		
//						point[3].load= pt.load;		//保存失败，恢复旧值（断电完蛋）。
//						point[3].ad= pt.ad;
//						point[3].used= pt.used;
//						
//						seg_flash_all(0);
//						seg_updata("Err00F");
//						
//						uartS("\nerr save load 3");
//						osDelay(1000);
//					}
//				}
//				else if(key == KEY_K1_ESC){
//					sta= 0;
//					disp_mv= 0;
//					
//					seg_updata(cur_item->content);
//					
//					//准备恢复校准过程中的滤波强度。
//					flag_para_update_fir= 'X';
//				}
//				
//				break;				
//			
//			default:
//				break;
//		}
//	}
//	else if(msg.type == MSG_TYPE_MV_WT){
//		uartS("\nmv");
//		if(disp_mv){
//			//显示mv值。
//			seg_mv_to_seg(msg.uv, msg.dat[0]);
//			set_one_seg(1,'C',0);
//			
//			ad= msg.ad;
//		}	
//	}
//}



///*标定第4点叶子菜单项处理函数。
//先显示LoAD4，确定后显示"Add ld"约1秒后，显示mv值。再确定，如果此时STAB有效，则进入设置标定4的称重值；无效（不稳）则死等。QQ如何退出死等状态？
//在显示mv值时，如果STAB指示灯常亮，按Enter键保存当前零点值，并进入下一个菜单项。
//*/
//void leaf_Fn_cal_load4(MSG_U msg)
//{
//	static uint8_t sta= 0;
//	static uint8_t idx_flash= 1;	//有效范围：1~6
//	static uint8_t disp_mv= 0;		//是否显示mv值。
//	static int32_t ad;				//和uV伴随而来的ad值。
//	uint16_t key;
//	char tmp8[8];
//	
//	
//	if(msg.type == MSG_TYPE_KEY){
//		key= msg.key;
//		
//		switch (sta){
//			case 0:	
//				if(KEY_K4_ENTER == key){
//					seg_updata("Add ld ");
//					osDelay(1000);
//					
//					disp_mv=1;
//					mode_mv_wt= MODE_MV;
//					
//					sta= 1;
//					
//					//滤波强度要变强。
//					flag_para_update_fir= 'C';
//				}
//				else if(KEY_K3_MODE == key){
//					//在同级菜单循环切换。
//					cur_item= cur_item->sibble;	
//					seg_updata(cur_item->content);	
//				}
//				else if(KEY_K1_ESC == key){
//					//返回上一级菜单。
//					cur_item= cur_item->parent;	
//					seg_updata(cur_item->content);
//				}
//				
//				break;
//				
//			case 1:
//				if(key == KEY_K4_ENTER){
//					
//					//需要判断当前STAB为1才能保存，否则什么也不做。
//					if(seg_stab_sta()){
//						disp_mv= 0;	//停止动态显示
//						
//						//保存当前mv值。
//						seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
//					
//						tmp8[0]= ' ';
//						if('C' == tmp8[1])
//							tmp8[1]= ' ';			//去掉第1个数码管的'C'。
//						tmp8[7]='\0';
//						point[4].uv= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
//						
//						
//						//
//						seg_updata("000000 ");
//						idx_flash= 1;
//						set_one_seg_flash(idx_flash, SEG_FLASH);
//						set_one_seg_point(6-para_xxx.pt_pos_idx, 1);	//pos_dot为0：个位小数点（也显示出来）；为1：十位小数点...
//						
//						sta= 2;
//					}
//				}
//				else if(key == KEY_K1_ESC){
//					sta= 0;
//					disp_mv= 0;
//					
//					seg_updata(cur_item->content);
//					
//					//滤波强度要恢复。
//					flag_para_update_fir= 'X';
//				}
//				
//				break;
//				
//			case 2:
//				//按OPT键调整数值，按MODE键移位，按Enter确认并进入同级下一个菜单。
//				if(key == KEY_K2_OPT){
//					inc_one_seg(idx_flash);
//				}
//				else if(key == KEY_K3_MODE){
//					set_one_seg_flash(idx_flash, SEG_LIGHT);
//					
//					idx_flash++;
//					if(6< idx_flash)
//						idx_flash= 1;
//					set_one_seg_flash(idx_flash, SEG_FLASH);
//				}
//				else if(key == KEY_K4_ENTER){
//					//保存旧值。
//					POINT pt;
//					pt.load= point[4].load;
//					pt.ad= point[4].ad;
//					pt.used= point[4].used;
//					
//					seg_copy_to_tmp(tmp8);		//将当前显示值拷贝到tmp8.
//					
//					tmp8[0]= ' ';
//					if('C' == tmp8[1])
//						tmp8[1]= ' ';			//去掉第1个数码管的'C'。
//					tmp8[7]='\0';
//					point[4].load= atoi(tmp8);	//将tmp8恢复为显示的uv值，并保存到point[0].uv。
//					point[4].ad= ad;
//					point[4].used= 1;
//					
//									
//					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
//						uartS("\nsave load 4");
//					
//						cur_item= cur_item->sibble;	
//						seg_updata(cur_item->content);

//						sta= 0;
//						seg_flash_all(0);
//						
//						//准备恢复校准过程中的滤波强度。
//						flag_para_update_fir= 'X';
//					}
//					else{		
//						point[4].load= pt.load;		//保存失败，恢复旧值（断电完蛋）。
//						point[4].ad= pt.ad;
//						point[4].used= pt.used;
//						
//						seg_flash_all(0);
//						seg_updata("Err00F");
//						
//						uartS("\nerr save load 4");
//						osDelay(1000);
//					}
//				}
//				else if(key == KEY_K1_ESC){
//					sta= 0;
//					disp_mv= 0;
//					
//					seg_updata(cur_item->content);
//					
//					//滤波强度要恢复。
//					flag_para_update_fir= 'X';
//				}
//				
//				break;				
//			
//			default:
//				break;
//		}
//	}
//	else if(msg.type == MSG_TYPE_MV_WT){
//		uartS("\nmv");
//		if(disp_mv){
//			//显示mv值。
//			seg_mv_to_seg(msg.uv, msg.dat[0]);
//			set_one_seg(1,'C',0);
//			
//			ad= msg.ad;
//		}	
//	}
//}






/*串口校准使能。
按OPT键进行切换（闪烁显示on或off），按Enter键进行确定。
*/
void leaf_Fn_cal_siocal(MSG_U msg)
{
	static uint8_t sta= 0;
	static uint8_t on_off= 0;	//有效范围：0,1.
	uint16_t key;	
	static uint8_t val_change;
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			//当前显示“PASS”，等待按enter.
			if(KEY_K4_ENTER == key){
				//根据pwd_setup_sw的值显示
				val_change= para_self.ser_cal_sw; 
				
				if(val_change){
					seg_updata("    on ");
				}
				else{
					seg_updata("   off ");
				}	
				
				seg_flash_all(1);		
				sta= 1;
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				cur_item= cur_item->sibble;	
				seg_updata(cur_item->content);	
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
			}
	
			break;
		case 1:
			//调整并确认
			if(KEY_K4_ENTER == key){
				//保存旧值。
				uint8_t val_tmp8= para_self.ser_cal_sw;
				para_self.ser_cal_sw= val_change;
				
				
				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
					uartS("\nsave para_self.ser_cal_sw;");
				
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);

					sta= 0;
					seg_flash_all(0);
				}
				else{
					para_self.ser_cal_sw= val_tmp8;		//保存失败，恢复旧值（断电完蛋）。
					
					seg_flash_all(0);
					seg_updata("Err00F");
					
					uartS("\nerr save para_self.ser_cal_sw");
					osDelay(1000);
				}
			}
			else if(key == KEY_K2_OPT){
				if(val_change){
					val_change= 0;
					seg_updata("   off ");
				}
				else{
					val_change= 1;
					seg_updata("    on ");
				}
			}
			else if(key == KEY_K3_MODE){
				if(val_change){
					val_change= 0;
					seg_updata("   off ");
				}
				else{
					val_change= 1;
					seg_updata("    on ");
				}
			}
			else if(KEY_K1_ESC == key){		
				seg_updata(cur_item->content);
				
				sta= 0;
				seg_flash_all(0);
			}
			break;
			
		default:
			break;
	}			
}



/*PASS(设置密码)叶子菜单项处理函数。
*/
void leaf_Fn_cal_pass(MSG_U msg)
{
	static uint8_t sta= 0;
//	static uint8_t idx_seg= 1;	//有效范围：1~6
	static char pass1[7];		//有效范围：1~6.	
	char tmp6[7];				//有效范围：1~6.	
	char tmp[7];				//临时变量。
	char str_i[7];
	
	uint16_t key;	
	
	if(msg.type != MSG_TYPE_KEY)
		return;
	
	key= msg.key;
	
	switch (sta){
		case 0:
			//当前显示“PASS”，等待按enter.
			if(KEY_K4_ENTER == key){
				seg_updata("------");		//调试要第1次输入密码。
				osDelay(1000);
				
				//!!int_menu是全局变量。
				int_menu.dig= 6;		
				int_menu.neg= 0;
				int_menu.val= 0;
				int_menu.max= 999999;
				int_menu.min= 0;
				
				sta= 1;
				sprintf(str_i, "%06d", int_menu.val); 
				seg_updata(str_i);	//测试序列：PASS
				
				//第1个‘0’闪
				int_menu.pos= SEG_L_1;
				x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
				//set_one_seg_flash(idx_seg, SEG_FLASH);
			}
			else if(KEY_K1_ESC == key){
				//返回上一级菜单。
				if(NULL != cur_item->parent){
					cur_item= cur_item->parent;	
					seg_updata(cur_item->content);
				}
			}
			else if(KEY_K2_OPT == key){
				//在同级菜单循环切换。
				if(NULL != cur_item->up_sibble){
					cur_item= cur_item->up_sibble;	
					seg_updata(cur_item->content);
				}
			}
			else if(KEY_K3_MODE == key){
				//在同级菜单循环切换。
				if(NULL != cur_item->sibble){
					cur_item= cur_item->sibble;	
					seg_updata(cur_item->content);	
				}
			}
			
			break;
			
		case 1:
			//第1次调整密码并确认：输入密码：按opt键调值，按mode键移位，按Enter键进行密码确认，按Esc键无效。
			if(key == KEY_K2_OPT){
				int_menu_inc_one_seg(0);	//x_seg_inc_one(int_menu.pos);
			}
			else if(key == KEY_K3_MODE){
				int_menu_change_pos();
//				x_seg_one_flash(int_menu.pos, DISP_X_MODE_NORM); 	//停止当前位置的数码管闪。set_one_seg_flash(idx_seg, SEG_LIGHT);	
//				
//				int_menu.pos++;
//				if(SEG_L_6< int_menu.pos)
//					int_menu.pos= SEG_L_1;
//				x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
			}
			else if(key == KEY_K4_ENTER){
				
				sprintf(pass1, "%06d", int_menu.val);	//x_seg_copy_to_tmp(pass1);	//seg_copy_to_tmp(pass1);
				
				x_seg_flash_all(0);
				seg_updata("======");		//调试要第2次输入密码。
				osDelay(1000);
				
				
				int_menu.dig= 6;		
				int_menu.neg= 0;
				int_menu.val= 0;
				
				sprintf(str_i, "%06d", int_menu.val); 
				seg_updata(str_i);	//测试序列：PASS
				
				//第1个‘0’闪
				int_menu.pos= SEG_L_1;
				x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
				
				sta= 2;
			}
			else if(key == KEY_K1_ESC){
				//返回上一级菜单。
				cur_item= cur_item->parent;	
				seg_updata(cur_item->content);
				
				sta= 0;
				x_seg_flash_all(0);
			}
			
			break;
			
		case 2:
			//第2次调整密码并确认。
			if(key == KEY_K2_OPT){
				int_menu_inc_one_seg(0);	//x_seg_inc_one(int_menu.pos);
			}
			else if(key == KEY_K3_MODE){
				int_menu_change_pos();
//				x_seg_one_flash(int_menu.pos, DISP_X_MODE_NORM); 	//停止当前位置的数码管闪。set_one_seg_flash(idx_seg, SEG_LIGHT);	
//				
//				int_menu.pos++;
//				if(SEG_L_6< int_menu.pos)
//					int_menu.pos= SEG_L_1;
//				x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
			}
			else if(key == KEY_K4_ENTER){
				x_seg_flash_all(0);
				
				sprintf(tmp6, "%06d", int_menu.val);	//x_seg_copy_to_tmp(tmp6);
				
				if(0 != pass_compare2(pass1, tmp6)){
					//2次密码不相同：显示错误后，重新开始。
					x_seg_flash_all(0);
					seg_updata("Error ");	//测试序列：PASS
					osDelay(2000);
					
					int_menu.dig= 6;		
					int_menu.neg= 0;
					int_menu.val= 0;
					
					sprintf(str_i, "%06d", int_menu.val); 
					seg_updata(str_i);	//测试序列：PASS
					
					//第1个‘0’闪
					int_menu.pos= SEG_L_1;
					x_seg_one_flash(int_menu.pos, DISP_X_MODE_FF); 
					
					sta= 1;
				}
				else{						
					//2次输入密码相同，准备保存新密码：保存旧密码 --> 申请保存 --> 
					uint8_t val_tmp8[6];
					for(uint8_t i= 0; i< 6; i++){
						val_tmp8[i]= para_self.pwd_cal[i];
						para_self.pwd_cal[i]= tmp6[i];
					}				
				
					if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_SELF)){
						uartS("\nsave pwd_cal");
					
						//设置密码ok
						seg_updata(" SUCC ");
						osDelay(1000);
						
						seg_updata("CALEnd");
						osDelay(1000);
						
						
						sta= 0;
						cur_item= cur_item->parent;
						seg_updata(cur_item->content);
					}
					else{
						for(uint8_t i= 0; i< 6; i++){
							para_self.pwd_cal[i]= val_tmp8[i];	//保存失败，恢复旧值（断电完蛋）。
						}	
						
						seg_updata("Err00F");
						
						uartS("\nerr save pwd_cal");
						osDelay(1000);
					};
				}
			}
			break;
			
		default:
			break;
	}	
}



/*无砝码零点标定的叶子菜单项处理函数。
在"o xxxx"时，按OPT键，进入输入零点mv值界面。
*/
static void leaf_Fn_cal_t_noload(MSG_U msg)
{

}



/*无砝码加载点标定的叶子菜单项处理函数。
在"C xxxx"时，按OPT键，进入输入加载点mv值界面，再输入重量值。
*/
static void leaf_Fn_cal_Load_noload(MSG_U msg)
{

}



///*读取过程中，显示"---"，读取完成并CRC8校验成功，显示"     o"。
//*/
//void leaf_Fn_cal_RdP(MSG_U msg)
//{
//	static uint8_t sta= 0;
//	char tmp8[8];
//	static uint8_t val_idx;
//	uint16_t key;	
//	static uint8_t val_change;
//	uint8_t idx_max;	//每次计算，也是合适。
//	char str[64];
//	
//	
//	if(msg.type != MSG_TYPE_KEY)
//		return;
//	
//	key= msg.key;
//	
//	switch (sta){
//		case 0:
//			if(KEY_K4_ENTER == key){
//				seg_updata("   ---");
//				
//				//读取传感器侧的单线芯片。
//				POINT pt_tmp[7];
//				POINT pt_bk[5];
//				int32_t cp_tmp;	//临时最大量程
//				uint16_t cp_H, cp_L;
//				
//				uint8_t crc8;
//				uint8_t u8array[16*5+4];
//				//将ds28的页0 -->pt_tmp[0]
//				ds28_rd_page(0, (uint8_t*)&pt_tmp[0]);	//无POINT.cp。
//				ds28_rd_page(1, (uint8_t*)&pt_tmp[1]);	//无POINT.cp。
//				ds28_rd_page(2, (uint8_t*)&pt_tmp[2]);	//无POINT.cp。
//				ds28_rd_page(3, (uint8_t*)&pt_tmp[3]);	//无POINT.cp。
//				ds28_rd_page(4, (uint8_t*)&pt_tmp[4]);	//无POINT.cp。
//				
//				ds28_rd_page(5, (uint8_t*)&pt_tmp[5]);	//最大量程
//				ds28_rd_page(6, (uint8_t*)&pt_tmp[6]);	//CRC8
//				
//				//先计算crc是否正确
//				crc8= (uint8_t)pt_tmp[6].used;
//				
//				memcpy(u8array+ 16*0, (uint8_t*)&pt_tmp[0], 16);
//				memcpy(u8array+ 16*1, (uint8_t*)&pt_tmp[1], 16);
//				memcpy(u8array+ 16*2, (uint8_t*)&pt_tmp[2], 16);
//				memcpy(u8array+ 16*3, (uint8_t*)&pt_tmp[3], 16);
//				memcpy(u8array+ 16*4, (uint8_t*)&pt_tmp[4], 16);
//				memcpy(u8array+ 16*5, (uint8_t*)&pt_tmp[5], 4);	//最大量程
//				
//				crc8= Crc8_Cal(u8array, 16*5+4);
//				
//				if(crc8 != (uint8_t)pt_tmp[6].used){
//					//读取后CRC8不对，可以重试。
//					seg_updata("Err101");
//					
//					uartS("err:CRC8");
//					
//					break;
//				}
//				
//				sprintf(str, "\n cp=%d, crc 0k", pt_tmp[5].used);
//				uartS(str);
//				
//				//将pt_tmp[]更新到point[]，保存前先备份（好像没用）。
//				uint8_t kk= 0;
//				
//				pt_bk[kk].used= point[kk].used;
//				pt_bk[kk].uv= point[kk].uv;
//				pt_bk[kk].ad= point[kk].ad;
//				pt_bk[kk].load= point[kk].load;
//				point[kk].used= pt_tmp[kk].used;
//				point[kk].uv= pt_tmp[kk].uv;
//				point[kk].ad= pt_tmp[kk].ad;
//				point[kk].load= pt_tmp[kk].load;
//				
//				kk++;	
//				//k=1
//				pt_bk[kk].used= point[kk].used;
//				pt_bk[kk].uv= point[kk].uv;
//				pt_bk[kk].ad= point[kk].ad;
//				pt_bk[kk].load= point[kk].load;
//				point[kk].used= pt_tmp[kk].used;
//				point[kk].uv= pt_tmp[kk].uv;
//				point[kk].ad= pt_tmp[kk].ad;
//				point[kk].load= pt_tmp[kk].load;
//				
//				kk++;	
//				//k=2
//				pt_bk[kk].used= point[kk].used;
//				pt_bk[kk].uv= point[kk].uv;
//				pt_bk[kk].ad= point[kk].ad;
//				pt_bk[kk].load= point[kk].load;
//				point[kk].used= pt_tmp[kk].used;
//				point[kk].uv= pt_tmp[kk].uv;
//				point[kk].ad= pt_tmp[kk].ad;
//				point[kk].load= pt_tmp[kk].load;
//				
//				kk++;	
//				//k=3
//				pt_bk[kk].used= point[kk].used;
//				pt_bk[kk].uv= point[kk].uv;
//				pt_bk[kk].ad= point[kk].ad;
//				pt_bk[kk].load= point[kk].load;
//				point[kk].used= pt_tmp[kk].used;
//				point[kk].uv= pt_tmp[kk].uv;
//				point[kk].ad= pt_tmp[kk].ad;
//				point[kk].load= pt_tmp[kk].load;
//				
//				kk++;	
//				//k=4
//				pt_bk[kk].used= point[kk].used;
//				pt_bk[kk].uv= point[kk].uv;
//				pt_bk[kk].ad= point[kk].ad;
//				pt_bk[kk].load= point[kk].load;
//				point[kk].used= pt_tmp[kk].used;
//				point[kk].uv= pt_tmp[kk].uv;
//				point[kk].ad= pt_tmp[kk].ad;
//				point[kk].load= pt_tmp[kk].load;
//				
//				
//				cp_H= para_xxx.fs_max_hi;
//				cp_L= para_xxx.fs_max_lo;
//				para_xxx.fs_max_hi= pt_tmp[5].used>> 16;
//				para_xxx.fs_max_lo= pt_tmp[5].used;
//				
//				
//				if(0 == para_to_flash_2(FLASH_UPDATE_MASK_PARA_XXXX)){
//					uartS("\nsave point[] and CP from DS28 to para_xxx");
//					
//					seg_updata("     o");
//					osDelay(1000);
//					
//					
//					cur_item= cur_item->sibble;	
//					seg_updata(cur_item->content);

//					sta= 0;
//					seg_flash_all(0);
//				}
//				else{
//					//编程失败，恢复之前值到RAM（QQ!!但未将这些值写入FLASH）。
//					para_xxx.fs_max_hi= cp_H;
//					para_xxx.fs_max_lo= cp_L;
//					
//					uint8_t kk= 0;
//					
//					point[kk].used= pt_bk[kk].used;
//					point[kk].uv= pt_bk[kk].uv;
//					point[kk].ad= pt_bk[kk].ad;
//					point[kk].load= pt_bk[kk].load;
//					
//					kk++;
//					point[kk].used= pt_bk[kk].used;
//					point[kk].uv= pt_bk[kk].uv;
//					point[kk].ad= pt_bk[kk].ad;
//					point[kk].load= pt_bk[kk].load;
//					
//					kk++;
//					point[kk].used= pt_bk[kk].used;
//					point[kk].uv= pt_bk[kk].uv;
//					point[kk].ad= pt_bk[kk].ad;
//					point[kk].load= pt_bk[kk].load;
//					
//					kk++;
//					point[kk].used= pt_bk[kk].used;
//					point[kk].uv= pt_bk[kk].uv;
//					point[kk].ad= pt_bk[kk].ad;
//					point[kk].load= pt_bk[kk].load;
//					
//										
//					seg_flash_all(0);
//					seg_updata("Err00F");
//					
//					uartS("\nerr save point[] and CP from DS28");
//					
//					osDelay(1000);
//				}
//			}
//			else if(KEY_K2_OPT == key){
//				//在同级菜单循环切换。
//				cur_item= cur_item->up_sibble;	
//				seg_updata(cur_item->content);
//			}
//			else if(KEY_K3_MODE == key){
//				//在同级菜单循环切换。
//				cur_item= cur_item->sibble;	
//				seg_updata(cur_item->content);	
//			}
//			else if(KEY_K1_ESC == key){
//				uartS("\nesc unit");
//				
//				cur_item= cur_item->parent;	
//				seg_updata(cur_item->content);
//			}
//	
//			break;
//			
//		default:
//			break;
//	}
//}



///*保存过程中，显示"---"，保存成功，显示"     o"，保存失败显示“Err100"。
//保存过程，是将仪表已标定值point[5]写入单线芯片，并增加CRC8。
//保存后，不必回读验证，因为写入函数已有回读（且回读是DS28E写入流程的一步）。
//*/
//void leaf_Fn_cal_SaP(MSG_U msg)
//{
//	static uint8_t sta= 0;
//	char tmp8[8];
//	static uint8_t val_idx;
//	uint16_t key;	
//	static uint8_t val_change;
//	uint8_t idx_max;	//每次计算，也是合适。
//	char str[48];
//	
//	
//	if(msg.type != MSG_TYPE_KEY)
//		return;
//	
//	key= msg.key;
//	
//	switch (sta){
//		case 0:
//			if(KEY_K4_ENTER == key){
//				seg_updata("   ---");
//				
//				//读取传感器侧的单线芯片。
//				POINT pt_tmp;			//用于写入最大量程和CRC8。
//				POINT pt_readback;			//用于写入最大量程和CRC8。
//				uint32_t cp_tmp;		//临时最大量程
//				uint16_t cp_H, cp_L;
//				
//				uint8_t crc8;
//				uint8_t u8array[16*5+4];
//				
//				pt_tmp.used= para_xxx.fs_max_hi;
//				pt_tmp.used<<= 16;
//				pt_tmp.used|= para_xxx.fs_max_lo;
//				pt_tmp.ad= 0x0;
//				pt_tmp.uv= 0x0;
//				pt_tmp.load= 0x0;
//				
////				//赋值（假的值）
////				point[0].used= 1;
////				point[0].ad= 0x123458;
////				point[0].uv= 0x123457;
////				point[0].load= 0x123459;
////				
////				point[1].used= 1;
////				point[1].ad= 0x11ABCB;
////				point[1].uv= 0x11ABCC;
////				point[1].load= 0x11ABCD;
////				
////				point[2].used= 1;
////				point[2].ad= 0x12ABCB;
////				point[2].uv= 0x12ABCC;
////				point[2].load= 0x12ABCD;
////				
////				point[3].used= 0;
////				point[3].ad= 0x13ABCB;
////				point[3].uv= 0x13ABCC;
////				point[3].load= 0x13ABCD;
////				
////				point[4].used= 0;
////				point[4].ad= 0x14ABCB;
////				point[4].uv= 0x14ABCC;
////				point[4].load= 0x14ABCD;
//				
//				
//				memcpy(u8array+ 16*0, (uint8_t*)&point[0], 16);
//				memcpy(u8array+ 16*1, (uint8_t*)&point[1], 16);
//				memcpy(u8array+ 16*2, (uint8_t*)&point[2], 16);
//				memcpy(u8array+ 16*3, (uint8_t*)&point[3], 16);
//				memcpy(u8array+ 16*4, (uint8_t*)&point[4], 16);
//				memcpy(u8array+ 16*5, (uint8_t*)&pt_tmp, 4);	//最大量程
//				
//				crc8= Crc8_Cal(u8array, 16*5+4);				//得到CRC8。
//				
//				//将ds28的页0 -->pt_tmp[0]
//				if(0 != ds28_wr_page(0, (uint8_t*)&point[0])){	//无POINT.cp。
//					uartS("err:wr DS28 p0");
//					break;
//				}
//				uartS("\nwr DS28 p0 ok");
//				
//				
//				if(0 != ds28_wr_page(1, (uint8_t*)&point[1])){	//无POINT.cp。
//					uartS("err:wr DS28 p1");
//					break;
//				}	
//				uartS("\nwr DS28 p1 ok");
//				
//				if(0 != ds28_wr_page(2, (uint8_t*)&point[2])){	//无POINT.cp。
//					uartS("err:wr DS28 p2");
//					break;
//				}
//				uartS("\nwr DS28 p2 ok");
//				
//				if(0 != ds28_wr_page(3, (uint8_t*)&point[3])){	//无POINT.cp。
//					uartS("err:wr DS28 p3");
//					break;
//				}
//				uartS("\nwr DS28 p3 ok");
//				
//				if(0 != ds28_wr_page(4, (uint8_t*)&point[4])){	//无POINT.cp。
//					uartS("err:wr DS28 p4");
//					break;
//				}
//				uartS("\nwr DS28 p4 ok");
//				
//				
//				
//				if(0 != ds28_wr_page(5, (uint8_t*)&pt_tmp)){	//最大量程
//					uartS("err:wr DS28 cp");
//					break;
//				}
//				uartS("\nwr DS28 p5 ok");
//				
//				pt_tmp.used= crc8;
//				if(0 != ds28_wr_page(6, (uint8_t*)&pt_tmp) ){	//CRC8
//					uartS("err:wr DS28 crc8");
//					break;
//				}
//				uartS("\nwr DS28 p6 ok");
//				
//				ds28_rd_page(0, (uint8_t*)&pt_readback);
//				sprintf(str, "\npt0: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
//				uartS(str);
//				
//				ds28_rd_page(1, (uint8_t*)&pt_readback);
//				sprintf(str, "\npt1: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
//				uartS(str);
//				
//				ds28_rd_page(2, (uint8_t*)&pt_readback);
//				sprintf(str, "\npt2: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
//				uartS(str);
//				
//				ds28_rd_page(3, (uint8_t*)&pt_readback);
//				sprintf(str, "\npt3: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
//				uartS(str);
//				
//				ds28_rd_page(4, (uint8_t*)&pt_readback);
//				sprintf(str, "\npt4: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
//				uartS(str);
//				
//				ds28_rd_page(5, (uint8_t*)&pt_readback);
//				sprintf(str, "\npt5: %08x-%08x-%08x-%08x", pt_readback.used, pt_readback.ad, pt_readback.uv, pt_readback.load);
//				uartS(str);
//				
//				ds28_rd_page(6, (uint8_t*)&pt_readback);
//				sprintf(str, "\npt6: %08x-%02x", pt_readback.used, (uint8_t)pt_readback.used);
//				uartS(str);
//				
//				
//				//保存成功，显示"    o"。
//				seg_updata("     o");
//			}
//			else if(KEY_K2_OPT == key){
//				//在同级菜单循环切换。
//				cur_item= cur_item->up_sibble;	
//				seg_updata(cur_item->content);
//			}
//			else if(KEY_K3_MODE == key){
//				//在同级菜单循环切换。
//				cur_item= cur_item->sibble;	
//				seg_updata(cur_item->content);	
//			}
//			else if(KEY_K1_ESC == key){
//				uartS("\nesc SA P  ");
//				
//				cur_item= cur_item->parent;	
//				seg_updata(cur_item->content);
//			}
//	
//			break;
//			
//		default:
//			break;
//	}
//}



/*将输入的mV值转换为adc采样值。
输入参数 uv: mV值（uv值为整数值，mV值为m.nnn格式）
返回值：对应的adc值（可能为负数）
说明：按激励电压为5.000V，增益为x64计算，即39.0625mV --> 7FFFFF，再简化为39063 --> 7FFFFF。
   uv       39063
------- =  ---------
   ret      0x7FFFFF
*/
static int32_t mv_to_ad(int32_t uv)
{
	int64_t ret;
	
	ret= uv;			//不能写为：ret= uv*0x7FFFFF; 要先转换，再计算。
	ret*=0x7FFFFF;
	ret/= (39063/2);	//Vref/2
	
	return (int32_t)ret;	
}



/*
*/
void offset_clear(void)
{
#ifdef OFFSET_DIV_N_F
	offset_div_n_f_man= 0;			//手动触发
	offset_div_n_f_pwr_on= 0;			//上电自动清零
	offset_div_n_f_trace= 0;			//零点跟踪
	offset_div_n_f_tare= 0;			//去皮操作
#else
	offset_man= 0;
	offset_pwr_on= 0;
	offset_trace= 0;
#endif
}



/*开门狗复位。
开启看门狗，设置一个很短时间。之后再死等待。
IWDG->PR默认为0，即divider /4。
Free-running downcouter.
Clocked from an independent RC oscillator(can operate in Standy and Stop modes):32K LSI.参见6.2.6。
Conditional Reset: when the downcounter value becomes less than 0x000。
QQ调试时发现，执行IWDG->KR=0xCCCC，会让RCC_CSR->LSIRDY为1，而RCC_CSR->LSION为0。奇怪QQ
*/
__NO_RETURN void wdg_rst(void)
{
	//实测，不需主动使能LSI，因为在使能IWDG（写入0xCCCC）时，LSIRDY置1。
	RCC->CSR|= RCC_CSR_LSION;
	while(0 == (RCC->CSR & RCC_CSR_LSIRDY));
	

	__disable_irq();			//写上吧。
	
	IWDG->KR= 0xCCCC;			//使能IWDG。
	IWDG->KR= 0x5555;			//使能访问IWDG寄存器。
	
	IWDG->RLR= 0x0001;
	while(IWDG->SR &0x0002);
	
	IWDG->KR= 0xAAAA;			//重载RLR，以加速复位。
	while(1);
}


///*用到的内置外设（TODO需要重写）：
//USART1，USART3，LPUART1，
//SPI2， SPI3，
//TIM2，TIM7，
//SYSTICK。
//*/
//void core_rst(void)
//{
//	__disable_irq();
//	
//	//复位已使用的设备，通过时钟复位。
//	RCC->APB1RSTR1|= RCC_APB1RSTR1_TIM2RST;
//	RCC->APB1RSTR1|= RCC_APB1RSTR1_TIM7RST;
//	RCC->APB1RSTR1|= RCC_APB1RSTR1_SPI2RST;
//	RCC->APB1RSTR1|= RCC_APB1RSTR1_SPI3RST;
//	
//	RCC->APB2RSTR|= RCC_APB2RSTR_USART1RST;
//	RCC->APB1RSTR1|= RCC_APB1RSTR2_LPUART1RST;		//RCC_APB1RSTR2_LPUART1;
//	RCC->APB1RSTR1|= RCC_APB1RSTR1_USART3RST;
//	
//	//Systick关中断
//	NVIC_DisableIRQ(SysTick_IRQn);
//	
//	//__NVIC_SystemReset();
//	
//	while(1);
//}

/*用到的内置外设：
USART1，USART3，LPUART1，
SPI2， SPI3，
TIM2，TIM7，
SYSTICK。
*/
__NO_RETURN void core_rst(void)
{
	__disable_irq();
	
	//复位已使用的设备，通过时钟复位。
	RCC->APB1RSTR1|= RCC_APB1RSTR1_TIM2RST;
	RCC->APB1RSTR1|= RCC_APB1RSTR1_TIM7RST;
	RCC->APB1RSTR1|= RCC_APB1RSTR1_SPI2RST;
	RCC->APB1RSTR1|= RCC_APB1RSTR1_SPI3RST;
	
	RCC->APB2RSTR|= RCC_APB2RSTR_USART1RST;
	RCC->APB1RSTR1|= RCC_APB1RSTR2_LPUART1RST;		//RCC_APB1RSTR2_LPUART1;
	RCC->APB1RSTR1|= RCC_APB1RSTR1_USART3RST;
	
	//Systick关中断
	NVIC_DisableIRQ(SysTick_IRQn);
	
	//__NVIC_SystemReset();	//实测也会复位GPIO。
	__DSB();                                                          /* Ensure all outstanding memory accesses included
																   buffered write are completed before reset */
	SCB->AIRCR  = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos)    |
					   (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) |
						SCB_AIRCR_VECTRESET_Msk    );         /* Keep priority group unchanged */
	__DSB();                                                          /* Ensure completion of memory access */

	for(;;)                                                           /* wait until reset */
	{
	__NOP();
	}
	
	while(1);
}


/*
*/
void wr_bkp0R(uint32_t dat)
{
	RCC->APB1ENR1|= RCC_APB1ENR1_PWREN;
	PWR->CR1|= PWR_CR1_DBP;
	
	RCC->BDCR|= RCC_BDCR_RTCSEL;			//选择HSE/32 as RTC clock.
	
	RCC->BDCR |= RCC_BDCR_RTCEN;			//使能RTC.
	
	RTC->BKP0R= dat;						//写入
	
	//RCC->BDCR|= RCC_BDCR_BDRST;			//复位BDCR。
	RCC->BDCR &= ~RCC_BDCR_RTCEN;			//使能RTC.
	RCC->APB1ENR1&= ~RCC_APB1ENR1_PWREN;	//关闭PWR时钟。
}

/************************ END OF FILE ************************/
